<!DOCTYPE html>
<html>
<head><meta name="generator" content="Hexo 3.8.0">
    

    
<!-- Tencent Speed -->
<script>var _speedMark = new Date()</script>
<!-- End Tencent Speed -->
<!-- Tencent Analysis -->
<script async src="//tajs.qq.com/stats?sId=false."></script>
<!-- End Tencent Analysis -->


    



    <meta charset="utf-8">
    
    
    <meta name="google-site-verification" content="CUm1VNyzpZuuHWWTWLOVfbkoMiz6Q9ccqUY5rMp9vcI">

    
    
    <title>周阳-阳哥JUC多线程及高并发部分 | Edward</title>
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    
    <meta name="theme-color" content="#3F51B5">
    
    
    <meta name="keywords" content="juc">
    <meta name="description" content="JUC多线程及高并发[TOC] 一、请你谈谈对volatile的理解​    Package java.util.concurrent—&amp;gt; AtomicInteger  Lock ReadWriteLock 1、volatile是java虚拟机提供的轻量级的同步机制保证可见性、不保证原子性、禁止指令重排  保证可见性 当多个线程访问同一个变量时，一个线程修改了这个变量的值，其他线程能够立即看">
<meta name="keywords" content="juc">
<meta property="og:type" content="article">
<meta property="og:title" content="周阳-阳哥JUC多线程及高并发部分">
<meta property="og:url" content="http://springcloud.xn--ses554g/2020/04/13/JUC多线程及高并发/index.html">
<meta property="og:site_name" content="Edward">
<meta property="og:description" content="JUC多线程及高并发[TOC] 一、请你谈谈对volatile的理解​    Package java.util.concurrent—&amp;gt; AtomicInteger  Lock ReadWriteLock 1、volatile是java虚拟机提供的轻量级的同步机制保证可见性、不保证原子性、禁止指令重排  保证可见性 当多个线程访问同一个变量时，一个线程修改了这个变量的值，其他线程能够立即看">
<meta property="og:locale" content="default">
<meta property="og:updated_time" content="2020-04-17T05:33:14.326Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="周阳-阳哥JUC多线程及高并发部分">
<meta name="twitter:description" content="JUC多线程及高并发[TOC] 一、请你谈谈对volatile的理解​    Package java.util.concurrent—&amp;gt; AtomicInteger  Lock ReadWriteLock 1、volatile是java虚拟机提供的轻量级的同步机制保证可见性、不保证原子性、禁止指令重排  保证可见性 当多个线程访问同一个变量时，一个线程修改了这个变量的值，其他线程能够立即看">
    
        <link rel="alternate" type="application/atom+xml" title="Edward" href="/atom.xml">
    
    <link rel="shortcut icon" href="/img/favicon.ico">
    <link rel="stylesheet" href="//unpkg.com/hexo-theme-material-indigo@latest/css/style.css">
    <script>window.lazyScripts=[]</script>

    <!-- custom head -->
    

    <script>
        (function(){
            var bp = document.createElement('script');
            var curProtocol = window.location.protocol.split(':')[0];
            if (curProtocol === 'https'){
                bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';
            }
            else{
                bp.src = 'http://push.zhanzhang.baidu.com/push.js';
            }
            var s = document.getElementsByTagName("script")[0];
            s.parentNode.insertBefore(bp, s);
        })();
    </script>

</head>

<body>
    <div id="loading" class="active"></div>

    <aside id="menu">
  <div class="inner flex-row-vertical">
    <a href="javascript:;" class="header-icon waves-effect waves-circle waves-light" id="menu-off">
        <i class="icon icon-lg icon-close"></i>
    </a>
    <div class="brand-wrap" style="background-image:url(/img/brand.jpg)">
      <div class="brand" style="padding-top: 30%;">
        <a href="/" class="avatar waves-effect waves-circle waves-light">
          <img src="/img/123.png">
        </a>
        <hgroup class="introduce">
          <h5 class="nickname">Edward</h5>
          <a href="mailto:zqmssbd@qq.com" title="zqmssbd@qq.com" class="mail">zqmssbd@qq.com</a>
        </hgroup>
      </div>
    </div>
    <div class="scroll-wrap flex-col">
      <ul class="nav">
        
            <li class="waves-block waves-effect">
              <a href="/">
                <i class="icon icon-lg icon-home"></i>
                主页
              </a>
            </li>
          
            <li class="waves-block waves-effect">
              <a href="/archives">
                <i class="icon icon-lg icon-archives"></i>
                Archives
              </a>
            </li>
          
            <li class="waves-block waves-effect">
              <a href="/tags">
                <i class="icon icon-lg icon-tags"></i>
                Tags
              </a>
            </li>
          
            <li class="waves-block waves-effect">
              <a href="/categories">
                <i class="icon icon-lg icon-th-list"></i>
                Categories
              </a>
            </li>
          
            <li class="waves-block waves-effect">
              <a href="https://github.com/zqmssbd" target="_blank">
                <i class="icon icon-lg icon-github"></i>
                Github
              </a>
            </li>
          
            <li class="waves-block waves-effect">
              <a href="https://weibo.com/5333276247" target="_blank">
                <i class="icon icon-lg icon-weibo"></i>
                Weibo
              </a>
            </li>
          
            <li class="waves-block waves-effect">
              <a href="https://gitee.com/Edward-Z" target="_blank">
                <i class="icon icon-lg icon-link"></i>
                码云
              </a>
            </li>
          
      </ul>
        <div id="tp-weather-widget"></div>
        <script>
            (function(a,h,g,f,e,d,c,b){b=function(){d=h.createElement(g);c=h.getElementsByTagName(g)[0];d.src=e;d.charset="utf-8";d.async=1;c.parentNode.insertBefore(d,c)};a["SeniverseWeatherWidgetObject"]=f;a[f]||(a[f]=function(){(a[f].q=a[f].q||[]).push(arguments)});a[f].l=+new Date();if(a.attachEvent){a.attachEvent("onload",b)}else{a.addEventListener("load",b,false)}}(window,document,"script","SeniverseWeatherWidget","//cdn.sencdn.com/widget2/static/js/bundle.js?t="+parseInt((new Date().getTime() / 100000000).toString(),10)));
            window.SeniverseWeatherWidget('show', {
                flavor: "bubble",
                location: "WT3Q0FW9ZJ3Q",
                geolocation: true,
                language: "zh-Hans",
                unit: "c",
                theme: "auto",
                token: "74eabe8a-0b6b-4a56-86ac-c773a4d98218",
                hover: "enabled",
                container: "tp-weather-widget"
            })
        </script>

        <link rel="stylesheet" href="/css/APlayer.css">
        <div id="player" class="aplayer aplayer-withlist aplayer-fixed" data-id="3895885" data-server="netease" data-type="playlist" data-order="random" data-fixed="true" data-listfolded="false" data-theme="#2D8CF0"></div>
        <script src="/js/APlayer.min.js"></script>
        <script src="/js/Meting.min.js"></script>

        


        

    </div>
  </div>
</aside>

    <main id="main">
        <header class="top-header" id="header">
    <div class="flex-row">
        <a href="javascript:;" class="header-icon waves-effect waves-circle waves-light on" id="menu-toggle">
          <i class="icon icon-lg icon-navicon"></i>
        </a>
        <div class="flex-col header-title ellipsis">周阳-阳哥JUC多线程及高并发部分</div>
        
        <div class="search-wrap" id="search-wrap">
            <a href="javascript:;" class="header-icon waves-effect waves-circle waves-light" id="back">
                <i class="icon icon-lg icon-chevron-left"></i>
            </a>
            <input type="text" id="key" class="search-input" autocomplete="off" placeholder="输入感兴趣的关键字">
            <a href="javascript:;" class="header-icon waves-effect waves-circle waves-light" id="search">
                <i class="icon icon-lg icon-search"></i>
            </a>
        </div>
        
        
        <a href="javascript:;" class="header-icon waves-effect waves-circle waves-light" id="menuShare">
            <i class="icon icon-lg icon-share-alt"></i>
        </a>
        
    </div>
</header>
<header class="content-header post-header">

    <div class="container fade-scale">
        <h1 class="title">周阳-阳哥JUC多线程及高并发部分</h1>
        <h5 class="title">你真的还不够，不够勤奋和努力。</h5>
        <h5 class="subtitle">
            
                <time datetime="2020-04-13T02:26:03.000Z" itemprop="datePublished" class="page-time">
  2020-04-13
</time>


	<ul class="article-category-list"><li class="article-category-list-item"><a class="article-category-list-link" href="/categories/juc/">juc</a></li></ul>

            
        </h5>
    </div>

    

    <script>
        (function(){
            var bp = document.createElement('script');
            var curProtocol = window.location.protocol.split(':')[0];
            if (curProtocol === 'https'){
                bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';
            }
            else{
                bp.src = 'http://push.zhanzhang.baidu.com/push.js';
            }
            var s = document.getElementsByTagName("script")[0];
            s.parentNode.insertBefore(bp, s);
        })();
    </script>
</header>


<div class="container body-wrap">
    
    <aside class="post-widget">
        <nav class="post-toc-wrap post-toc-shrink" id="post-toc">
            <h4>TOC</h4>
            <ol class="post-toc"><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#JUC多线程及高并发"><span class="post-toc-number">1.</span> <span class="post-toc-text">JUC多线程及高并发</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#一、请你谈谈对volatile的理解"><span class="post-toc-number">1.1.</span> <span class="post-toc-text">一、请你谈谈对volatile的理解</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#1、volatile是java虚拟机提供的轻量级的同步机制"><span class="post-toc-number">1.1.1.</span> <span class="post-toc-text">1、volatile是java虚拟机提供的轻量级的同步机制</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#2、JMM（java内存模型）"><span class="post-toc-number">1.1.2.</span> <span class="post-toc-text">2、JMM（java内存模型）</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#3、你在那些地方用过volatile"><span class="post-toc-number">1.1.3.</span> <span class="post-toc-text">3、你在那些地方用过volatile</span></a></li></ol></li><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#二、CAS你知道吗"><span class="post-toc-number">1.2.</span> <span class="post-toc-text">二、CAS你知道吗</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#1、compareAndSet—-比较并交换"><span class="post-toc-number">1.2.1.</span> <span class="post-toc-text">1、compareAndSet—-比较并交换</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#2、CAS底层原理？对Unsafe的理解"><span class="post-toc-number">1.2.2.</span> <span class="post-toc-text">2、CAS底层原理？对Unsafe的理解</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#3、CAS缺点"><span class="post-toc-number">1.2.3.</span> <span class="post-toc-text">3、CAS缺点</span></a></li></ol></li><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#三、原子类AtomicInteger的ABA问题？原子更新引用？"><span class="post-toc-number">1.3.</span> <span class="post-toc-text">三、原子类AtomicInteger的ABA问题？原子更新引用？</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#1、ABA如何产生"><span class="post-toc-number">1.3.1.</span> <span class="post-toc-text">1、ABA如何产生</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#2、如何解决？原子引用"><span class="post-toc-number">1.3.2.</span> <span class="post-toc-text">2、如何解决？原子引用</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#3、时间戳的原子引用"><span class="post-toc-number">1.3.3.</span> <span class="post-toc-text">3、时间戳的原子引用</span></a></li></ol></li><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#四、我们知道ArrayList是线程不安全的，请编写一个不安全的案例并给出解决方案"><span class="post-toc-number">1.4.</span> <span class="post-toc-text">四、我们知道ArrayList是线程不安全的，请编写一个不安全的案例并给出解决方案</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#1、线程不安全"><span class="post-toc-number">1.4.1.</span> <span class="post-toc-text">1、线程不安全</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#2、导致原因"><span class="post-toc-number">1.4.2.</span> <span class="post-toc-text">2、导致原因</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#3、解决方法：-CopyOnWriteArrayList"><span class="post-toc-number">1.4.3.</span> <span class="post-toc-text">3、解决方法：**CopyOnWriteArrayList</span></a></li></ol></li><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#五、公平锁、非公平锁、可重入锁、递归锁、自旋锁？手写自旋锁"><span class="post-toc-number">1.5.</span> <span class="post-toc-text">五、公平锁、非公平锁、可重入锁、递归锁、自旋锁？手写自旋锁</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#1、公平锁、非公平锁"><span class="post-toc-number">1.5.1.</span> <span class="post-toc-text">1、公平锁、非公平锁</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#2、可重入所（递归锁）"><span class="post-toc-number">1.5.2.</span> <span class="post-toc-text">2、可重入所（递归锁）</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#3、独占锁-写锁-共享锁-读锁-互斥锁"><span class="post-toc-number">1.5.3.</span> <span class="post-toc-text">3、独占锁(写锁)/共享锁(读锁)/互斥锁</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#4、自旋锁"><span class="post-toc-number">1.5.4.</span> <span class="post-toc-text">4、自旋锁</span></a></li></ol></li><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#六、CountDownLatch-CyclicBarrier-Semaphore使用过吗"><span class="post-toc-number">1.6.</span> <span class="post-toc-text">六、CountDownLatch/CyclicBarrier/Semaphore使用过吗</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#1、CountDownLatch（火箭发射倒计时）"><span class="post-toc-number">1.6.1.</span> <span class="post-toc-text">1、CountDownLatch（火箭发射倒计时）</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#2、CyclicBarrier（集齐七颗龙珠召唤神龙）"><span class="post-toc-number">1.6.2.</span> <span class="post-toc-text">2、CyclicBarrier（集齐七颗龙珠召唤神龙）</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#3、Semaphore信号量"><span class="post-toc-number">1.6.3.</span> <span class="post-toc-text">3、Semaphore信号量</span></a></li></ol></li><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#七、阻塞队列"><span class="post-toc-number">1.7.</span> <span class="post-toc-text">七、阻塞队列</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#1、队列和阻塞队列"><span class="post-toc-number">1.7.1.</span> <span class="post-toc-text">1、队列和阻塞队列</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#2、为什么用？有什么好处？"><span class="post-toc-number">1.7.2.</span> <span class="post-toc-text">2、为什么用？有什么好处？</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#3、BlockingQueue的核心方法"><span class="post-toc-number">1.7.3.</span> <span class="post-toc-text">3、BlockingQueue的核心方法</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#4、架构梳理-种类分析"><span class="post-toc-number">1.7.4.</span> <span class="post-toc-text">4、架构梳理+种类分析</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#5、用在哪里"><span class="post-toc-number">1.7.5.</span> <span class="post-toc-text">5、用在哪里</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#6、synchronized和lock有什么区别？用新的lock有什么好处？请举例"><span class="post-toc-number">1.7.6.</span> <span class="post-toc-text">6、synchronized和lock有什么区别？用新的lock有什么好处？请举例</span></a></li></ol></li><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#八、线程池用过吗？ThreadPoolExecutor谈谈你的理解"><span class="post-toc-number">1.8.</span> <span class="post-toc-text">八、线程池用过吗？ThreadPoolExecutor谈谈你的理解</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#1、Callable接口的使用"><span class="post-toc-number">1.8.1.</span> <span class="post-toc-text">1、Callable接口的使用</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#2、为什么使用线程池"><span class="post-toc-number">1.8.2.</span> <span class="post-toc-text">2、为什么使用线程池</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#3、线程池如何使用"><span class="post-toc-number">1.8.3.</span> <span class="post-toc-text">3、线程池如何使用</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#4、线程池的几个重要参数介绍"><span class="post-toc-number">1.8.4.</span> <span class="post-toc-text">4、线程池的几个重要参数介绍</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#5、线程池的底层工作原理"><span class="post-toc-number">1.8.5.</span> <span class="post-toc-text">5、线程池的底层工作原理</span></a></li></ol></li><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#九、线程池用过吗？生产上你如何设置合理参数"><span class="post-toc-number">1.9.</span> <span class="post-toc-text">九、线程池用过吗？生产上你如何设置合理参数</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#1、线程池的拒绝策略"><span class="post-toc-number">1.9.1.</span> <span class="post-toc-text">1、线程池的拒绝策略</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#2、你在工作中单一的-固定数的-可变的三种创建线程池的方法，用哪个多"><span class="post-toc-number">1.9.2.</span> <span class="post-toc-text">2、你在工作中单一的/固定数的/可变的三种创建线程池的方法，用哪个多</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#3、你在工作中时如何使用线程池的，是否自定义过线程池使用"><span class="post-toc-number">1.9.3.</span> <span class="post-toc-text">3、你在工作中时如何使用线程池的，是否自定义过线程池使用</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#4、合理配置线程池你是如何考虑的？"><span class="post-toc-number">1.9.4.</span> <span class="post-toc-text">4、合理配置线程池你是如何考虑的？</span></a></li></ol></li><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#十、死锁编码及定位分析"><span class="post-toc-number">1.10.</span> <span class="post-toc-text">十、死锁编码及定位分析</span></a></li></ol></li></ol>
            <!--<div id="toc" class="toc-article">-->
                <!--<strong class="toc-title">文章目录</strong>-->
                <!--<ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#JUC多线程及高并发"><span class="toc-number">1.</span> <span class="toc-text">JUC多线程及高并发</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#一、请你谈谈对volatile的理解"><span class="toc-number">1.1.</span> <span class="toc-text">一、请你谈谈对volatile的理解</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#1、volatile是java虚拟机提供的轻量级的同步机制"><span class="toc-number">1.1.1.</span> <span class="toc-text">1、volatile是java虚拟机提供的轻量级的同步机制</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2、JMM（java内存模型）"><span class="toc-number">1.1.2.</span> <span class="toc-text">2、JMM（java内存模型）</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3、你在那些地方用过volatile"><span class="toc-number">1.1.3.</span> <span class="toc-text">3、你在那些地方用过volatile</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#二、CAS你知道吗"><span class="toc-number">1.2.</span> <span class="toc-text">二、CAS你知道吗</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#1、compareAndSet—-比较并交换"><span class="toc-number">1.2.1.</span> <span class="toc-text">1、compareAndSet—-比较并交换</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2、CAS底层原理？对Unsafe的理解"><span class="toc-number">1.2.2.</span> <span class="toc-text">2、CAS底层原理？对Unsafe的理解</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3、CAS缺点"><span class="toc-number">1.2.3.</span> <span class="toc-text">3、CAS缺点</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#三、原子类AtomicInteger的ABA问题？原子更新引用？"><span class="toc-number">1.3.</span> <span class="toc-text">三、原子类AtomicInteger的ABA问题？原子更新引用？</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#1、ABA如何产生"><span class="toc-number">1.3.1.</span> <span class="toc-text">1、ABA如何产生</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2、如何解决？原子引用"><span class="toc-number">1.3.2.</span> <span class="toc-text">2、如何解决？原子引用</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3、时间戳的原子引用"><span class="toc-number">1.3.3.</span> <span class="toc-text">3、时间戳的原子引用</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#四、我们知道ArrayList是线程不安全的，请编写一个不安全的案例并给出解决方案"><span class="toc-number">1.4.</span> <span class="toc-text">四、我们知道ArrayList是线程不安全的，请编写一个不安全的案例并给出解决方案</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#1、线程不安全"><span class="toc-number">1.4.1.</span> <span class="toc-text">1、线程不安全</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2、导致原因"><span class="toc-number">1.4.2.</span> <span class="toc-text">2、导致原因</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3、解决方法：-CopyOnWriteArrayList"><span class="toc-number">1.4.3.</span> <span class="toc-text">3、解决方法：**CopyOnWriteArrayList</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#五、公平锁、非公平锁、可重入锁、递归锁、自旋锁？手写自旋锁"><span class="toc-number">1.5.</span> <span class="toc-text">五、公平锁、非公平锁、可重入锁、递归锁、自旋锁？手写自旋锁</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#1、公平锁、非公平锁"><span class="toc-number">1.5.1.</span> <span class="toc-text">1、公平锁、非公平锁</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2、可重入所（递归锁）"><span class="toc-number">1.5.2.</span> <span class="toc-text">2、可重入所（递归锁）</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3、独占锁-写锁-共享锁-读锁-互斥锁"><span class="toc-number">1.5.3.</span> <span class="toc-text">3、独占锁(写锁)/共享锁(读锁)/互斥锁</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4、自旋锁"><span class="toc-number">1.5.4.</span> <span class="toc-text">4、自旋锁</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#六、CountDownLatch-CyclicBarrier-Semaphore使用过吗"><span class="toc-number">1.6.</span> <span class="toc-text">六、CountDownLatch/CyclicBarrier/Semaphore使用过吗</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#1、CountDownLatch（火箭发射倒计时）"><span class="toc-number">1.6.1.</span> <span class="toc-text">1、CountDownLatch（火箭发射倒计时）</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2、CyclicBarrier（集齐七颗龙珠召唤神龙）"><span class="toc-number">1.6.2.</span> <span class="toc-text">2、CyclicBarrier（集齐七颗龙珠召唤神龙）</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3、Semaphore信号量"><span class="toc-number">1.6.3.</span> <span class="toc-text">3、Semaphore信号量</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#七、阻塞队列"><span class="toc-number">1.7.</span> <span class="toc-text">七、阻塞队列</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#1、队列和阻塞队列"><span class="toc-number">1.7.1.</span> <span class="toc-text">1、队列和阻塞队列</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2、为什么用？有什么好处？"><span class="toc-number">1.7.2.</span> <span class="toc-text">2、为什么用？有什么好处？</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3、BlockingQueue的核心方法"><span class="toc-number">1.7.3.</span> <span class="toc-text">3、BlockingQueue的核心方法</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4、架构梳理-种类分析"><span class="toc-number">1.7.4.</span> <span class="toc-text">4、架构梳理+种类分析</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#5、用在哪里"><span class="toc-number">1.7.5.</span> <span class="toc-text">5、用在哪里</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#6、synchronized和lock有什么区别？用新的lock有什么好处？请举例"><span class="toc-number">1.7.6.</span> <span class="toc-text">6、synchronized和lock有什么区别？用新的lock有什么好处？请举例</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#八、线程池用过吗？ThreadPoolExecutor谈谈你的理解"><span class="toc-number">1.8.</span> <span class="toc-text">八、线程池用过吗？ThreadPoolExecutor谈谈你的理解</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#1、Callable接口的使用"><span class="toc-number">1.8.1.</span> <span class="toc-text">1、Callable接口的使用</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2、为什么使用线程池"><span class="toc-number">1.8.2.</span> <span class="toc-text">2、为什么使用线程池</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3、线程池如何使用"><span class="toc-number">1.8.3.</span> <span class="toc-text">3、线程池如何使用</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4、线程池的几个重要参数介绍"><span class="toc-number">1.8.4.</span> <span class="toc-text">4、线程池的几个重要参数介绍</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#5、线程池的底层工作原理"><span class="toc-number">1.8.5.</span> <span class="toc-text">5、线程池的底层工作原理</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#九、线程池用过吗？生产上你如何设置合理参数"><span class="toc-number">1.9.</span> <span class="toc-text">九、线程池用过吗？生产上你如何设置合理参数</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#1、线程池的拒绝策略"><span class="toc-number">1.9.1.</span> <span class="toc-text">1、线程池的拒绝策略</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2、你在工作中单一的-固定数的-可变的三种创建线程池的方法，用哪个多"><span class="toc-number">1.9.2.</span> <span class="toc-text">2、你在工作中单一的/固定数的/可变的三种创建线程池的方法，用哪个多</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3、你在工作中时如何使用线程池的，是否自定义过线程池使用"><span class="toc-number">1.9.3.</span> <span class="toc-text">3、你在工作中时如何使用线程池的，是否自定义过线程池使用</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4、合理配置线程池你是如何考虑的？"><span class="toc-number">1.9.4.</span> <span class="toc-text">4、合理配置线程池你是如何考虑的？</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#十、死锁编码及定位分析"><span class="toc-number">1.10.</span> <span class="toc-text">十、死锁编码及定位分析</span></a></li></ol></li></ol>-->
            <!--</div>-->
        </nav>
    </aside>




<article id="post-JUC多线程及高并发" class="post-article article-type-post fade" itemprop="blogPost">

    <div class="post-card">
        <h1 class="post-card-title">周阳-阳哥JUC多线程及高并发部分</h1>
        <div class="post-meta">
            <time class="post-time" title="2020-04-13 10:26:03" datetime="2020-04-13T02:26:03.000Z" itemprop="datePublished">2020-04-13</time>

            
	<ul class="article-category-list"><li class="article-category-list-item"><a class="article-category-list-link" href="/categories/juc/">juc</a></li></ul>



            
<span id="busuanzi_container_page_pv" title="文章总阅读量" style="display:none">
    <i class="icon icon-eye icon-pr"></i><span id="busuanzi_value_page_pv"></span>
</span>


        </div>
        <div class="post-content" id="post-content" itemprop="postContent">
            <h2 id="JUC多线程及高并发"><a href="#JUC多线程及高并发" class="headerlink" title="JUC多线程及高并发"></a>JUC多线程及高并发</h2><p>[TOC]</p>
<h3 id="一、请你谈谈对volatile的理解"><a href="#一、请你谈谈对volatile的理解" class="headerlink" title="一、请你谈谈对volatile的理解"></a>一、请你谈谈对volatile的理解</h3><p>​    <code>Package java.util.concurrent</code>—&gt; <code>AtomicInteger</code>  <code>Lock</code> <code>ReadWriteLock</code></p>
<h4 id="1、volatile是java虚拟机提供的轻量级的同步机制"><a href="#1、volatile是java虚拟机提供的轻量级的同步机制" class="headerlink" title="1、volatile是java虚拟机提供的轻量级的同步机制"></a>1、volatile是java虚拟机提供的轻量级的同步机制</h4><p>保证可见性、不保证原子性、禁止指令重排</p>
<ol>
<li><p>保证可见性</p>
<p>当多个线程访问同一个变量时，一个线程修改了这个变量的值，其他线程能够立即看到修改的值</p>
<p>当不添加volatile关键字时示例：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.jian8.juc;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.TimeUnit;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 1验证volatile的可见性</span></span><br><span class="line"><span class="comment"> * 1.1 如果int num = 0，number变量没有添加volatile关键字修饰</span></span><br><span class="line"><span class="comment"> * 1.2 添加了volatile，可以解决可见性</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">VolatileDemo</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        visibilityByVolatile();<span class="comment">//验证volatile的可见性</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * volatile可以保证可见性，及时通知其他线程，主物理内存的值已经被修改</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">visibilityByVolatile</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        MyData myData = <span class="keyword">new</span> MyData();</span><br><span class="line"></span><br><span class="line">        <span class="comment">//第一个线程</span></span><br><span class="line">        <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">            System.out.println(Thread.currentThread().getName() + <span class="string">"\t come in"</span>);</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                <span class="comment">//线程暂停3s</span></span><br><span class="line">                TimeUnit.SECONDS.sleep(<span class="number">3</span>);</span><br><span class="line">                myData.addToSixty();</span><br><span class="line">                System.out.println(Thread.currentThread().getName() + <span class="string">"\t update value:"</span> + myData.num);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">                <span class="comment">// TODO Auto-generated catch block</span></span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;, <span class="string">"thread1"</span>).start();</span><br><span class="line">        <span class="comment">//第二个线程是main线程</span></span><br><span class="line">        <span class="keyword">while</span> (myData.num == <span class="number">0</span>) &#123;</span><br><span class="line">            <span class="comment">//如果myData的num一直为零，main线程一直在这里循环</span></span><br><span class="line">        &#125;</span><br><span class="line">        System.out.println(Thread.currentThread().getName() + <span class="string">"\t mission is over, num value is "</span> + myData.num);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MyData</span> </span>&#123;</span><br><span class="line">    <span class="comment">//    int num = 0;</span></span><br><span class="line">    <span class="keyword">volatile</span> <span class="keyword">int</span> num = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">addToSixty</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.num = <span class="number">60</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>输出结果：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">thread1	 come in</span><br><span class="line">thread1	 update value:<span class="number">60</span></span><br><span class="line"><span class="comment">//线程进入死循环</span></span><br></pre></td></tr></table></figure>
<p>当我们加上<code>volatile</code>关键字后，<code>volatile int num = 0;</code>输出结果为：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">thread1	 come in</span><br><span class="line">thread1	 update value:<span class="number">60</span></span><br><span class="line">main	 mission is over, num value is <span class="number">60</span></span><br><span class="line"><span class="comment">//程序没有死循环，结束执行</span></span><br></pre></td></tr></table></figure>
</li>
</ol>
<ol start="2">
<li><p>==不保证原子性==</p>
<p>原子性：不可分割、完整性，即某个线程正在做某个具体业务时，中间不可以被加塞或者被分割，需要整体完整，要么同时成功，要么同时失败</p>
<p>验证示例（变量添加volatile关键字，方法不添加synchronized）：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.jian8.juc;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.TimeUnit;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.atomic.AtomicInteger;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 1验证volatile的可见性</span></span><br><span class="line"><span class="comment"> *  1.1 如果int num = 0，number变量没有添加volatile关键字修饰</span></span><br><span class="line"><span class="comment"> * 1.2 添加了volatile，可以解决可见性</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * 2.验证volatile不保证原子性</span></span><br><span class="line"><span class="comment"> *  2.1 原子性指的是什么</span></span><br><span class="line"><span class="comment"> *      不可分割、完整性，即某个线程正在做某个具体业务时，中间不可以被加塞或者被分割，需要整体完整，要么同时成功，要么同时失败</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">VolatileDemo</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line"><span class="comment">//        visibilityByVolatile();//验证volatile的可见性</span></span><br><span class="line">        atomicByVolatile();<span class="comment">//验证volatile不保证原子性</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * volatile可以保证可见性，及时通知其他线程，主物理内存的值已经被修改</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">	<span class="comment">//public static void visibilityByVolatile()&#123;&#125;</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * volatile不保证原子性</span></span><br><span class="line"><span class="comment">     * 以及使用Atomic保证原子性</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">atomicByVolatile</span><span class="params">()</span></span>&#123;</span><br><span class="line">        MyData myData = <span class="keyword">new</span> MyData();</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">1</span>; i &lt;= <span class="number">20</span>; i++)&#123;</span><br><span class="line">            <span class="keyword">new</span> Thread(() -&gt;&#123;</span><br><span class="line">                <span class="keyword">for</span>(<span class="keyword">int</span> j = <span class="number">1</span>; j &lt;= <span class="number">1000</span>; j++)&#123;</span><br><span class="line">                    myData.addSelf();</span><br><span class="line">                    myData.atomicAddSelf();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;,<span class="string">"Thread "</span>+i).start();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//等待上面的线程都计算完成后，再用main线程取得最终结果值</span></span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            TimeUnit.SECONDS.sleep(<span class="number">4</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">while</span> (Thread.activeCount()&gt;<span class="number">2</span>)&#123;</span><br><span class="line">            Thread.yield();</span><br><span class="line">        &#125;</span><br><span class="line">        System.out.println(Thread.currentThread().getName()+<span class="string">"\t finally num value is "</span>+myData.num);</span><br><span class="line">        System.out.println(Thread.currentThread().getName()+<span class="string">"\t finally atomicnum value is "</span>+myData.atomicInteger);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MyData</span> </span>&#123;</span><br><span class="line">    <span class="comment">//    int num = 0;</span></span><br><span class="line">    <span class="keyword">volatile</span> <span class="keyword">int</span> num = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">addToSixty</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.num = <span class="number">60</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">addSelf</span><span class="params">()</span></span>&#123;</span><br><span class="line">        num++;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    AtomicInteger atomicInteger = <span class="keyword">new</span> AtomicInteger();</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">atomicAddSelf</span><span class="params">()</span></span>&#123;</span><br><span class="line">        atomicInteger.getAndIncrement();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>执行三次结果为：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//1.</span></span><br><span class="line">main	 <span class="keyword">finally</span> num value is <span class="number">19580</span>	</span><br><span class="line">main	 <span class="keyword">finally</span> atomicnum value is <span class="number">20000</span></span><br><span class="line"><span class="comment">//2.</span></span><br><span class="line">main	 <span class="keyword">finally</span> num value is <span class="number">19999</span></span><br><span class="line">main	 <span class="keyword">finally</span> atomicnum value is <span class="number">20000</span></span><br><span class="line"><span class="comment">//3.</span></span><br><span class="line">main	 <span class="keyword">finally</span> num value is <span class="number">18375</span></span><br><span class="line">main	 <span class="keyword">finally</span> atomicnum value is <span class="number">20000</span></span><br><span class="line"><span class="comment">//num并没有达到20000</span></span><br></pre></td></tr></table></figure>
</li>
</ol>
<ol start="3">
<li><p>禁止指令重排</p>
<p>有序性：在计算机执行程序时，为了提高性能，编译器和处理器常常会对<strong>==指令做重拍==</strong>，一般分以下三种</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">graph LR</span><br><span class="line">	源代码 --&gt; id1[&quot;编译器优化的重排&quot;]</span><br><span class="line">	id1 --&gt; id2[指令并行的重排]</span><br><span class="line">	id2 --&gt; id3[内存系统的重排]</span><br><span class="line">	id3 --&gt; 最终执行的指令</span><br><span class="line">	style id1 fill:#ff8000;</span><br><span class="line">	style id2 fill:#fab400;</span><br><span class="line">	style id3 fill:#ffd557;</span><br></pre></td></tr></table></figure>
<p>单线程环境里面确保程序最终执行结果和代码顺序执行的结果一致。</p>
<p>处理器在进行重排顺序是必须要考虑指令之间的<strong>==数据依赖性==</strong></p>
<p>==多线程环境中线程交替执行，由于编译器优化重排的存在，两个线程中使用的变量能否保证一致性时无法确定的，结果无法预测==</p>
<p>重排代码实例：</p>
<p>声明变量：<code>int a,b,x,y=0</code></p>
<p>| 线程1          | 线程2          |<br>| ————– | ————– |<br>| x = a;         | y = b;         |<br>| b = 1;         | a = 2;         |<br>| 结          果 | x = 0      y=0 |</p>
<p>如果编译器对这段程序代码执行重排优化后，可能出现如下情况：</p>
<p>| 线程1          | 线程2          |<br>| ————– | ————– |<br>| b = 1;         | a = 2;         |<br>| x= a;          | y = b;         |<br>| 结          果 | x = 2      y=1 |</p>
<p>这个结果说明在多线程环境下，由于编译器优化重排的存在，两个线程中使用的变量能否保证一致性是无法确定的</p>
<p>volatile实现禁止指令重排，从而避免了多线程环境下程序出现乱序执行的现象</p>
<p><strong>==内存屏障==</strong>（Memory Barrier）又称内存栅栏，是一个CPU指令，他的作用有两个：</p>
<ol>
<li>保证特定操作的执行顺序</li>
<li>保证某些变量的内存可见性（利用该特性实现volatile的内存可见性）</li>
</ol>
<p>由于编译器和处理器都能执行指令重排优化。如果在之零件插入一i奥Memory Barrier则会告诉编译器和CPU，不管什么指令都不能和这条Memory Barrier指令重排顺序，也就是说==通过插入内存屏障禁止在内存屏障前后的指令执行重排序优化==。内存屏障另外一个作用是强制刷出各种CPU的缓存数据，因此任何CPU上的线程都能读取到这些数据的最新版本。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">graph TB</span><br><span class="line">    subgraph </span><br><span class="line">    bbbb[&quot;对Volatile变量进行读操作时，&lt;br&gt;回在读操作之前加入一条load屏障指令，&lt;br&gt;从内存中读取共享变量&quot;]</span><br><span class="line">    ids6[Volatile]--&gt;red3[LoadLoad屏障]</span><br><span class="line">    red3--&gt;id7[&quot;禁止下边所有普通读操作&lt;br&gt;和上面的volatile读重排序&quot;]</span><br><span class="line">    red3--&gt;red4[LoadStore屏障]</span><br><span class="line">    red4--&gt;id9[&quot;禁止下边所有普通写操作&lt;br&gt;和上面的volatile读重排序&quot;]</span><br><span class="line">    red4--&gt;id8[普通读]</span><br><span class="line">    id8--&gt;普通写</span><br><span class="line">    end</span><br><span class="line">    subgraph </span><br><span class="line">    aaaa[&quot;对Volatile变量进行写操作时，&lt;br&gt;回在写操作后加入一条store屏障指令，&lt;br&gt;将工作内存中的共享变量值刷新回到主内存&quot;]</span><br><span class="line">    id1[普通读]--&gt;id2[普通写]</span><br><span class="line">    id2--&gt;red1[StoreStore屏障]</span><br><span class="line">    red1--&gt;id3[&quot;禁止上面的普通写和&lt;br&gt;下面的volatile写重排序&quot;]</span><br><span class="line">    red1--&gt;id4[&quot;Volatile写&quot;]</span><br><span class="line">    id4--&gt;red2[StoreLoad屏障]</span><br><span class="line">    red2--&gt;id5[&quot;防止上面的volatile写和&lt;br&gt;下面可能有的volatile读写重排序&quot;]</span><br><span class="line">    end</span><br><span class="line">    style red1 fill:#ff0000;</span><br><span class="line">    style red2 fill:#ff0000;</span><br><span class="line">    style red4 fill:#ff0000;</span><br><span class="line">    style red3 fill:#ff0000;</span><br><span class="line">    style aaaa fill:#ffff00;</span><br><span class="line">    style bbbb fill:#ffff00;</span><br></pre></td></tr></table></figure>
</li>
</ol>
<h4 id="2、JMM（java内存模型）"><a href="#2、JMM（java内存模型）" class="headerlink" title="2、JMM（java内存模型）"></a>2、JMM（java内存模型）</h4><p>JMM（Java Memory Model）本身是一种抽象的概念，并不真实存在，他描述的时一组规则或规范，通过这组规范定义了程序中各个变量（包括实例字段，静态字段和构成数组对象的元素）的访问方式。</p>
<p><strong>JMM关于同步的规定：</strong></p>
<ol>
<li>线程解锁前，必须把共享变量的值刷新回主内存</li>
<li>线程加锁前，必须读取主内存的最新值到自己的工作内存</li>
<li>加锁解锁时同一把锁</li>
</ol>
<p>由于JVM运行程序的实体是线程，而每个线程创建时JVM都会为其创建一个工作内存（有的成为栈空间），工作内存是每个线程的私有数据区域，而java内存模型中规定所有变量都存储在<strong>==主内存==</strong>，主内存是贡献内存区域，所有线程都可以访问，<strong>==但线程对变量的操作（读取赋值等）必须在工作内存中进行，首先概要将变量从主内存拷贝到自己的工作内存空间，然后对变量进行操作，操作完成后再将变量写回主内存，==</strong>不能直接操作主内存中的变量，各个线程中的工作内存中存储着主内存的<strong>==变量副本拷贝==</strong>，因此不同的线程件无法访问对方的工作内存，线程间的通信（传值）必须通过主内存来完成，期间要访问过程如下图：!<em>**</em><a href="/img/1559049634(1"></a>.jpg)</p>
<ol>
<li>可见性</li>
<li>原子性</li>
<li>有序性</li>
</ol>
<h4 id="3、你在那些地方用过volatile"><a href="#3、你在那些地方用过volatile" class="headerlink" title="3、你在那些地方用过volatile"></a>3、你在那些地方用过volatile</h4><p>当普通单例模式在多线程情况下：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SingletonDemo</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> SingletonDemo instance = <span class="keyword">null</span>;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="title">SingletonDemo</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(Thread.currentThread().getName() + <span class="string">"\t 构造方法SingletonDemo（）"</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> SingletonDemo <span class="title">getInstance</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (instance == <span class="keyword">null</span>) &#123;</span><br><span class="line">            instance = <span class="keyword">new</span> SingletonDemo();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> instance;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="comment">//构造方法只会被执行一次</span></span><br><span class="line"><span class="comment">//        System.out.println(getInstance() == getInstance());</span></span><br><span class="line"><span class="comment">//        System.out.println(getInstance() == getInstance());</span></span><br><span class="line"><span class="comment">//        System.out.println(getInstance() == getInstance());</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">//并发多线程后，构造方法会在一些情况下执行多次</span></span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">10</span>; i++) &#123;</span><br><span class="line">            <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">                SingletonDemo.getInstance();</span><br><span class="line">            &#125;, <span class="string">"Thread "</span> + i).start();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>其构造方法在一些情况下会被执行多次</p>
<p>解决方式：</p>
<ol>
<li><p><strong>单例模式DCL代码</strong></p>
<p>DCL （Double Check Lock双端检锁机制）在加锁前和加锁后都进行一次判断</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> SingletonDemo <span class="title">getInstance</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (instance == <span class="keyword">null</span>) &#123;</span><br><span class="line">        <span class="keyword">synchronized</span> (SingletonDemo.class) &#123;</span><br><span class="line">            <span class="keyword">if</span> (instance == <span class="keyword">null</span>) &#123;</span><br><span class="line">                instance = <span class="keyword">new</span> SingletonDemo();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> instance;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>大部分运行结果构造方法只会被执行一次</strong>，但指令重排机制会让程序很小的几率出现构造方法被执行多次</p>
<p><strong>==DCL（双端检锁）机制不一定线程安全==</strong>，原因时有指令重排的存在，加入volatile可以禁止指令重排</p>
<p>原因是在某一个线程执行到第一次检测，读取到instance不为null时，instance的引用对象可能==没有完成初始化==。instance=new SingleDemo();可以被分为一下三步（伪代码）：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">memory = allocate();<span class="comment">//1.分配对象内存空间</span></span><br><span class="line">instance(memory);	<span class="comment">//2.初始化对象</span></span><br><span class="line">instance = memory;	<span class="comment">//3.设置instance执行刚分配的内存地址，此时instance!=null</span></span><br></pre></td></tr></table></figure>
<p>步骤2和步骤3不存在数据依赖关系，而且无论重排前还是重排后程序的执行结果在单线程中并没有改变，因此这种重排优化时允许的，<strong>如果3步骤提前于步骤2，但是instance还没有初始化完成</strong></p>
<p>但是指令重排只会保证串行语义的执行的一致性（单线程），但并不关心多线程间的语义一致性。</p>
<p>==所以当一条线程访问instance不为null时，由于instance示例未必已初始化完成，也就造成了线程安全问题。==</p>
</li>
<li><p><strong>单例模式volatile代码</strong></p>
<p>为解决以上问题，可以将SingletongDemo实例上加上volatile</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">volatile</span> SingletonDemo instance = <span class="keyword">null</span>;</span><br></pre></td></tr></table></figure>
</li>
</ol>
<h3 id="二、CAS你知道吗"><a href="#二、CAS你知道吗" class="headerlink" title="二、CAS你知道吗"></a>二、CAS你知道吗</h3><h4 id="1、compareAndSet—-比较并交换"><a href="#1、compareAndSet—-比较并交换" class="headerlink" title="1、compareAndSet—-比较并交换"></a>1、compareAndSet—-比较并交换</h4><p>AtomicInteger.conpareAndSet(int expect, indt update)</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">boolean</span> <span class="title">compareAndSet</span><span class="params">(<span class="keyword">int</span> expect, <span class="keyword">int</span> update)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> unsafe.compareAndSwapInt(<span class="keyword">this</span>, valueOffset, expect, update);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>第一个参数为拿到的期望值，如果期望值没有一致，进行update赋值，如果期望值不一致，证明数据被修改过，返回fasle，取消赋值</p>
<p>例子：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.jian8.juc.cas;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.atomic.AtomicInteger;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 1.CAS是什么？</span></span><br><span class="line"><span class="comment"> * 1.1比较并交换</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CASDemo</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">       checkCAS();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">checkCAS</span><span class="params">()</span></span>&#123;</span><br><span class="line">        AtomicInteger atomicInteger = <span class="keyword">new</span> AtomicInteger(<span class="number">5</span>);</span><br><span class="line">        System.out.println(atomicInteger.compareAndSet(<span class="number">5</span>, <span class="number">2019</span>) + <span class="string">"\t current data is "</span> + atomicInteger.get());</span><br><span class="line">        System.out.println(atomicInteger.compareAndSet(<span class="number">5</span>, <span class="number">2014</span>) + <span class="string">"\t current data is "</span> + atomicInteger.get());</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>输出结果为：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">true</span>	 current data is <span class="number">2019</span></span><br><span class="line"><span class="keyword">false</span>	 current data is <span class="number">2019</span></span><br></pre></td></tr></table></figure>
<h4 id="2、CAS底层原理？对Unsafe的理解"><a href="#2、CAS底层原理？对Unsafe的理解" class="headerlink" title="2、CAS底层原理？对Unsafe的理解"></a>2、CAS底层原理？对Unsafe的理解</h4><p>比较当前工作内存中的值和主内存中的值，如果相同则执行规定操作，否则继续比较知道主内存和工作内存中的值一直为止</p>
<ol>
<li><p>atomicInteger.getAndIncrement();</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">int</span> <span class="title">getAndIncrement</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> unsafe.getAndAddInt(<span class="keyword">this</span>, valueOffset, <span class="number">1</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
<li><p>Unsafe</p>
<ul>
<li><p>是CAS核心类，由于Java方法无法直接访问地层系统，需要通过本地（native）方法来访问，Unsafe相当于一个后门，基于该类可以直接操作特定内存数据。Unsafe类存在于<code>sun.misc</code>包中，其内部方法操作可以像C的指针一样直接操作内存，因为Java中CAS操作的执行依赖于Unsafe类的方法。</p>
<p><strong>Unsafe类中的所有方法都是native修饰的，也就是说Unsafe类中的方法都直接调用操作系统底层资源执行相应任务</strong></p>
</li>
<li><p>变量valueOffset，表示该变量值在内存中的偏移地址，因为Unsafe就是根据内存便宜地址获取数据的</p>
</li>
<li><p>变量value用volatile修饰，保证多线程之间的可见性</p>
</li>
</ul>
</li>
<li><p>CAS是什么</p>
<p>CAS全称呼Compare-And-Swap，它是一条CPU并发原语</p>
<p>他的功能是判断内存某个位置的值是否为预期值，如果是则更改为新的值，这个过程是原子的。</p>
<p>CAS并发原语体现在JAVA语言中就是sun.misc.Unsafe类中各个方法。调用Unsafe类中的CAS方法，JVM会帮我们实现CAS汇编指令。这是一种完全依赖于硬件的功能，通过他实现了原子操作。由于CAS是一种系统原语，原语属于操作系统用语范畴，是由若干条指令组成的，用于完成某个功能的一个过程，并且原语的执行必须是连续的，在执行过程中不允许被中断，也就是说CAS是一条CPU的原子指令，不会造成数据不一致问题。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//unsafe.getAndAddInt</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">int</span> <span class="title">getAndAddInt</span><span class="params">(Object var1, <span class="keyword">long</span> var2, <span class="keyword">int</span> var4)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">int</span> var5;</span><br><span class="line">        <span class="keyword">do</span> &#123;</span><br><span class="line">            var5 = <span class="keyword">this</span>.getIntVolatile(var1, var2);</span><br><span class="line">        &#125; <span class="keyword">while</span>(!<span class="keyword">this</span>.compareAndSwapInt(var1, var2, var5, var5 + var4));</span><br><span class="line">        <span class="keyword">return</span> var5;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>
<p>var1 AtomicInteger对象本身</p>
<p>var2 该对象的引用地址</p>
<p>var4 需要变动的数据</p>
<p>var5 通过var1 var2找出的主内存中真实的值</p>
<p>用该对象前的值与var5比较；</p>
<p>如果相同，更新var5+var4并且返回true，</p>
<p>如果不同，继续去之然后再比较，直到更新完成</p>
</li>
</ol>
<h4 id="3、CAS缺点"><a href="#3、CAS缺点" class="headerlink" title="3、CAS缺点"></a>3、CAS缺点</h4><ol>
<li><p><strong> 循环时间长，开销大</strong></p>
<p>例如getAndAddInt方法执行，有个do while循环，如果CAS失败，一直会进行尝试，如果CAS长时间不成功，可能会给CPU带来很大的开销</p>
</li>
<li><p><strong>只能保证一个共享变量的原子操作</strong></p>
<p>对多个共享变量操作时，循环CAS就无法保证操作的原子性，这个时候就可以用锁来保证原子性</p>
</li>
<li><p><strong>ABA问题</strong></p>
</li>
</ol>
<h3 id="三、原子类AtomicInteger的ABA问题？原子更新引用？"><a href="#三、原子类AtomicInteger的ABA问题？原子更新引用？" class="headerlink" title="三、原子类AtomicInteger的ABA问题？原子更新引用？"></a>三、原子类AtomicInteger的ABA问题？原子更新引用？</h3><h4 id="1、ABA如何产生"><a href="#1、ABA如何产生" class="headerlink" title="1、ABA如何产生"></a>1、ABA如何产生</h4><p>CAS算法实现一个重要前提需要去除内存中某个时刻的数据并在当下时刻比较并替换，那么在这个时间差类会导致数据的变化。</p>
<p>比如<strong>线程1</strong>从内存位置V取出A，<strong>线程2</strong>同时也从内存取出A，并且线程2进行一些操作将值改为B，然后线程2又将V位置数据改成A，这时候线程1进行CAS操作发现内存中的值依然时A，然后线程1操作成功。</p>
<p>==尽管线程1的CAS操作成功，但是不代表这个过程没有问题==</p>
<h4 id="2、如何解决？原子引用"><a href="#2、如何解决？原子引用" class="headerlink" title="2、如何解决？原子引用"></a>2、如何解决？原子引用</h4><p>示例代码：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> juc.cas;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> lombok.AllArgsConstructor;</span><br><span class="line"><span class="keyword">import</span> lombok.Getter;</span><br><span class="line"><span class="keyword">import</span> lombok.ToString;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.atomic.AtomicReference;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">AtomicRefrenceDemo</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        User z3 = <span class="keyword">new</span> User(<span class="string">"张三"</span>, <span class="number">22</span>);</span><br><span class="line">        User l4 = <span class="keyword">new</span> User(<span class="string">"李四"</span>, <span class="number">23</span>);</span><br><span class="line">        AtomicReference&lt;User&gt; atomicReference = <span class="keyword">new</span> AtomicReference&lt;&gt;();</span><br><span class="line">        atomicReference.set(z3);</span><br><span class="line">        System.out.println(atomicReference.compareAndSet(z3, l4) + <span class="string">"\t"</span> + atomicReference.get().toString());</span><br><span class="line">        System.out.println(atomicReference.compareAndSet(z3, l4) + <span class="string">"\t"</span> + atomicReference.get().toString());</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Getter</span></span><br><span class="line"><span class="meta">@ToString</span></span><br><span class="line"><span class="meta">@AllArgsConstructor</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">User</span> </span>&#123;</span><br><span class="line">    String userName;</span><br><span class="line">    <span class="keyword">int</span> age;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>输出结果</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">true</span>	<span class="title">User</span><span class="params">(userName=李四, age=<span class="number">23</span>)</span></span></span><br><span class="line"><span class="function"><span class="keyword">false</span>	<span class="title">User</span><span class="params">(userName=李四, age=<span class="number">23</span>)</span></span></span><br></pre></td></tr></table></figure>
<h4 id="3、时间戳的原子引用"><a href="#3、时间戳的原子引用" class="headerlink" title="3、时间戳的原子引用"></a>3、时间戳的原子引用</h4><p>新增机制，修改版本号</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.jian8.juc.cas;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.TimeUnit;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.atomic.AtomicReference;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.atomic.AtomicStampedReference;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * ABA问题解决</span></span><br><span class="line"><span class="comment"> * AtomicStampedReference</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ABADemo</span> </span>&#123;</span><br><span class="line">    <span class="keyword">static</span> AtomicReference&lt;Integer&gt; atomicReference = <span class="keyword">new</span> AtomicReference&lt;&gt;(<span class="number">100</span>);</span><br><span class="line">    <span class="keyword">static</span> AtomicStampedReference&lt;Integer&gt; atomicStampedReference = <span class="keyword">new</span> AtomicStampedReference&lt;&gt;(<span class="number">100</span>, <span class="number">1</span>);</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">"=====以下时ABA问题的产生====="</span>);</span><br><span class="line">        <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">            atomicReference.compareAndSet(<span class="number">100</span>, <span class="number">101</span>);</span><br><span class="line">            atomicReference.compareAndSet(<span class="number">101</span>, <span class="number">100</span>);</span><br><span class="line">        &#125;, <span class="string">"Thread 1"</span>).start();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                <span class="comment">//保证线程1完成一次ABA操作</span></span><br><span class="line">                TimeUnit.SECONDS.sleep(<span class="number">1</span>);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">            System.out.println(atomicReference.compareAndSet(<span class="number">100</span>, <span class="number">2019</span>) + <span class="string">"\t"</span> + atomicReference.get());</span><br><span class="line">        &#125;, <span class="string">"Thread 2"</span>).start();</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            TimeUnit.SECONDS.sleep(<span class="number">2</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">        System.out.println(<span class="string">"=====以下时ABA问题的解决====="</span>);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">            <span class="keyword">int</span> stamp = atomicStampedReference.getStamp();</span><br><span class="line">            System.out.println(Thread.currentThread().getName() + <span class="string">"\t第1次版本号"</span> + stamp);</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                TimeUnit.SECONDS.sleep(<span class="number">2</span>);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">            atomicStampedReference.compareAndSet(<span class="number">100</span>, <span class="number">101</span>, atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + <span class="number">1</span>);</span><br><span class="line">            System.out.println(Thread.currentThread().getName() + <span class="string">"\t第2次版本号"</span> + atomicStampedReference.getStamp());</span><br><span class="line">            atomicStampedReference.compareAndSet(<span class="number">101</span>, <span class="number">100</span>, atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + <span class="number">1</span>);</span><br><span class="line">            System.out.println(Thread.currentThread().getName() + <span class="string">"\t第3次版本号"</span> + atomicStampedReference.getStamp());</span><br><span class="line">        &#125;, <span class="string">"Thread 3"</span>).start();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">            <span class="keyword">int</span> stamp = atomicStampedReference.getStamp();</span><br><span class="line">            System.out.println(Thread.currentThread().getName() + <span class="string">"\t第1次版本号"</span> + stamp);</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                TimeUnit.SECONDS.sleep(<span class="number">4</span>);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">boolean</span> result = atomicStampedReference.compareAndSet(<span class="number">100</span>, <span class="number">2019</span>, stamp, stamp + <span class="number">1</span>);</span><br><span class="line"></span><br><span class="line">            System.out.println(Thread.currentThread().getName() + <span class="string">"\t修改是否成功"</span> + result + <span class="string">"\t当前最新实际版本号："</span> + atomicStampedReference.getStamp());</span><br><span class="line">            System.out.println(Thread.currentThread().getName() + <span class="string">"\t当前最新实际值："</span> + atomicStampedReference.getReference());</span><br><span class="line">        &#125;, <span class="string">"Thread 4"</span>).start();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>输出结果：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">=====以下时ABA问题的产生=====</span><br><span class="line"><span class="keyword">true</span>	<span class="number">2019</span></span><br><span class="line">=====以下时ABA问题的解决=====</span><br><span class="line">Thread <span class="number">3</span>	第<span class="number">1</span>次版本号<span class="number">1</span></span><br><span class="line">Thread <span class="number">4</span>	第<span class="number">1</span>次版本号<span class="number">1</span></span><br><span class="line">Thread <span class="number">3</span>	第<span class="number">2</span>次版本号<span class="number">2</span></span><br><span class="line">Thread <span class="number">3</span>	第<span class="number">3</span>次版本号<span class="number">3</span></span><br><span class="line">Thread <span class="number">4</span>	修改是否成功<span class="keyword">false</span>	当前最新实际版本号：<span class="number">3</span></span><br><span class="line">Thread <span class="number">4</span>	当前最新实际值：<span class="number">100</span></span><br></pre></td></tr></table></figure>
<h3 id="四、我们知道ArrayList是线程不安全的，请编写一个不安全的案例并给出解决方案"><a href="#四、我们知道ArrayList是线程不安全的，请编写一个不安全的案例并给出解决方案" class="headerlink" title="四、我们知道ArrayList是线程不安全的，请编写一个不安全的案例并给出解决方案"></a>四、我们知道ArrayList是线程不安全的，请编写一个不安全的案例并给出解决方案</h3><p>HashSet与ArrayList一致 HashMap</p>
<p>HashSet底层是一个HashMap，存储的值放在HashMap的key里，value存储了一个PRESENT的静态Object对象</p>
<h4 id="1、线程不安全"><a href="#1、线程不安全" class="headerlink" title="1、线程不安全"></a>1、线程不安全</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.jian8.juc.collection;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.ArrayList;</span><br><span class="line"><span class="keyword">import</span> java.util.List;</span><br><span class="line"><span class="keyword">import</span> java.util.UUID;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 集合类不安全问题</span></span><br><span class="line"><span class="comment"> * ArrayList</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ContainerNotSafeDemo</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        notSafe();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 故障现象</span></span><br><span class="line"><span class="comment">     * java.util.ConcurrentModificationException</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">notSafe</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        List&lt;String&gt; list = <span class="keyword">new</span> ArrayList&lt;&gt;();</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i &lt;= <span class="number">30</span>; i++) &#123;</span><br><span class="line">            <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">                list.add(UUID.randomUUID().toString().substring(<span class="number">0</span>, <span class="number">8</span>));</span><br><span class="line">                System.out.println(list);</span><br><span class="line">            &#125;, <span class="string">"Thread "</span> + i).start();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>报错：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Exception in thread <span class="string">"Thread 10"</span> java.util.ConcurrentModificationException</span><br></pre></td></tr></table></figure>
<h4 id="2、导致原因"><a href="#2、导致原因" class="headerlink" title="2、导致原因"></a>2、导致原因</h4><p>并发正常修改导致</p>
<p>一个人正在写入，另一个同学来抢夺，导致数据不一致，并发修改异常</p>
<h4 id="3、解决方法：-CopyOnWriteArrayList"><a href="#3、解决方法：-CopyOnWriteArrayList" class="headerlink" title="3、解决方法：**CopyOnWriteArrayList"></a>3、解决方法：**CopyOnWriteArrayList</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">List&lt;String&gt; list = new Vector&lt;&gt;();//Vector线程安全</span><br><span class="line">List&lt;String&gt; list = Collections.synchronizedList(new ArrayList&lt;&gt;());//使用辅助类</span><br><span class="line">List&lt;String&gt; list = new CopyOnWriteArrayList&lt;&gt;();//写时复制，读写分离</span><br><span class="line"></span><br><span class="line">Map&lt;String, String&gt; map = new ConcurrentHashMap&lt;&gt;();</span><br><span class="line">Map&lt;String, String&gt; map = Collections.synchronizedMap(new HashMap&lt;&gt;());</span><br></pre></td></tr></table></figure>
<p>CopyOnWriteArrayList.add方法：</p>
<p>CopyOnWrite容器即写时复制，往一个元素添加容器的时候，不直接往当前容器Object[]添加，而是先将当前容器Object[]进行copy，复制出一个新的容器Object[] newElements，让后新的容器添加元素，添加完元素之后，再将原容器的引用指向新的容器setArray(newElements),这样做可以对CopyOnWrite容器进行并发的读，而不需要加锁，因为当前容器不会添加任何元素，所以CopyOnWrite容器也是一种读写分离的思想，读和写不同的容器</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">add</span><span class="params">(E e)</span> </span>&#123;</span><br><span class="line">       <span class="keyword">final</span> ReentrantLock lock = <span class="keyword">this</span>.lock;</span><br><span class="line">       lock.lock();</span><br><span class="line">       <span class="keyword">try</span> &#123;</span><br><span class="line">           Object[] elements = getArray();</span><br><span class="line">           <span class="keyword">int</span> len = elements.length;</span><br><span class="line">           Object[] newElements = Arrays.copyOf(elements, len + <span class="number">1</span>);</span><br><span class="line">           newElements[len] = e;</span><br><span class="line">           setArray(newElements);</span><br><span class="line">           <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">       &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">           lock.unlock();</span><br><span class="line">       &#125;</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure>
<h3 id="五、公平锁、非公平锁、可重入锁、递归锁、自旋锁？手写自旋锁"><a href="#五、公平锁、非公平锁、可重入锁、递归锁、自旋锁？手写自旋锁" class="headerlink" title="五、公平锁、非公平锁、可重入锁、递归锁、自旋锁？手写自旋锁"></a>五、公平锁、非公平锁、可重入锁、递归锁、自旋锁？手写自旋锁</h3><h4 id="1、公平锁、非公平锁"><a href="#1、公平锁、非公平锁" class="headerlink" title="1、公平锁、非公平锁"></a>1、公平锁、非公平锁</h4><ol>
<li><p><strong>是什么</strong></p>
<p>公平锁就是先来后到、非公平锁就是允许加塞，<code>Lock lock = new ReentrantLock(Boolean fair);</code> 默认非公平。</p>
<ul>
<li><p><strong>==公平锁==</strong>是指多个线程按照申请锁的顺序来获取锁，类似排队打饭。</p>
</li>
<li><p><strong>==非公平锁==</strong>是指多个线程获取锁的顺序并不是按照申请锁的顺序，有可能后申请的线程优先获取锁，在高并发的情况下，有可能会造成优先级反转或者节现象。</p>
</li>
</ul>
</li>
<li><p><strong>两者区别</strong></p>
<ul>
<li><p><strong>公平锁</strong>：Threads acquire  a fair lock in the order in which they requested it</p>
<p>公平锁，就是很公平，在并发环境中，每个线程在获取锁时，会先查看此锁维护的等待队列，如果为空，或者当前线程就是等待队列的第一个，就占有锁，否则就会加入到等待队列中，以后会按照FIFO的规则从队列中取到自己。</p>
</li>
<li><p><strong>非公平锁</strong>：a nonfair lock permits barging: threads requesting a lock can jump ahead of the queue of waiting threads if the lock happens to be available when it is requested.</p>
<p>非公平锁比较粗鲁，上来就直接尝试占有额，如果尝试失败，就再采用类似公平锁那种方式。</p>
</li>
</ul>
</li>
<li><p><strong>other</strong></p>
<p>对Java ReentrantLock而言，通过构造函数指定该锁是否公平，磨粉是非公平锁，非公平锁的优点在于吞吐量比公平锁大</p>
<p>对Synchronized而言，是一种非公平锁</p>
</li>
</ol>
<h4 id="2、可重入所（递归锁）"><a href="#2、可重入所（递归锁）" class="headerlink" title="2、可重入所（递归锁）"></a>2、可重入所（递归锁）</h4><ol>
<li><p><strong>递归锁是什么</strong></p>
<p>指的时同一线程外层函数获得锁之后，内层递归函数仍然能获取该锁的代码，在同一个线程在外层方法获取锁的时候，在进入内层方法会自动获取锁，也就是说，==线程可以进入任何一个它已经拥有的锁所同步着的代码块==</p>
</li>
<li><p><strong>ReentrantLock/Synchronized 就是一个典型的可重入锁</strong></p>
</li>
<li><p><strong>可重入锁最大的作用是避免死锁</strong></p>
</li>
<li><p><strong>代码示例</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.jian8.juc.lock;</span><br><span class="line"></span><br><span class="line">####</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        Phone phone = <span class="keyword">new</span> Phone();</span><br><span class="line">        <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                phone.sendSMS();</span><br><span class="line">            &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;, <span class="string">"Thread 1"</span>).start();</span><br><span class="line">        <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                phone.sendSMS();</span><br><span class="line">            &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;, <span class="string">"Thread 2"</span>).start();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Phone</span></span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">sendSMS</span><span class="params">()</span><span class="keyword">throws</span> Exception</span>&#123;</span><br><span class="line">        System.out.println(Thread.currentThread().getName()+<span class="string">"\t -----invoked sendSMS()"</span>);</span><br><span class="line">        Thread.sleep(<span class="number">3000</span>);</span><br><span class="line">        sendEmail();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">sendEmail</span><span class="params">()</span> <span class="keyword">throws</span> Exception</span>&#123;</span><br><span class="line">        System.out.println(Thread.currentThread().getName()+<span class="string">"\t +++++invoked sendEmail()"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.jian8.juc.lock;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.locks.Lock;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.locks.ReentrantLock;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ReentrantLockDemo</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        Mobile mobile = <span class="keyword">new</span> Mobile();</span><br><span class="line">        <span class="keyword">new</span> Thread(mobile).start();</span><br><span class="line">        <span class="keyword">new</span> Thread(mobile).start();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Mobile</span> <span class="keyword">implements</span> <span class="title">Runnable</span></span>&#123;</span><br><span class="line">    Lock lock = <span class="keyword">new</span> ReentrantLock();</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        get();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">get</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        lock.lock();</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            System.out.println(Thread.currentThread().getName()+<span class="string">"\t invoked get()"</span>);</span><br><span class="line">            set();</span><br><span class="line">        &#125;<span class="keyword">finally</span> &#123;</span><br><span class="line">            lock.unlock();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">set</span><span class="params">()</span></span>&#123;</span><br><span class="line">        lock.lock();</span><br><span class="line">        <span class="keyword">try</span>&#123;</span><br><span class="line">            System.out.println(Thread.currentThread().getName()+<span class="string">"\t invoked set()"</span>);</span><br><span class="line">        &#125;<span class="keyword">finally</span> &#123;</span><br><span class="line">            lock.unlock();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
</ol>
<h4 id="3、独占锁-写锁-共享锁-读锁-互斥锁"><a href="#3、独占锁-写锁-共享锁-读锁-互斥锁" class="headerlink" title="3、独占锁(写锁)/共享锁(读锁)/互斥锁"></a>3、独占锁(写锁)/共享锁(读锁)/互斥锁</h4><ol>
<li><p><strong>概念</strong></p>
<ul>
<li><p><strong>独占锁</strong>：指该锁一次只能被一个线程所持有，对ReentrantLock和Synchronized而言都是独占锁</p>
</li>
<li><p><strong>共享锁</strong>：只该锁可被多个线程所持有</p>
<p><strong>ReentrantReadWriteLock</strong>其读锁是共享锁，写锁是独占锁</p>
</li>
<li><p><strong>互斥锁</strong>：读锁的共享锁可以保证并发读是非常高效的，读写、写读、写写的过程是互斥的</p>
</li>
</ul>
</li>
<li><p><strong>代码示例</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.jian8.juc.lock;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.HashMap;</span><br><span class="line"><span class="keyword">import</span> java.util.Map;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.TimeUnit;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.locks.Lock;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.locks.ReentrantReadWriteLock;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 多个线程同时读一个资源类没有任何问题，所以为了满足并发量，读取共享资源应该可以同时进行。</span></span><br><span class="line"><span class="comment"> * 但是</span></span><br><span class="line"><span class="comment"> * 如果有一个线程象取写共享资源来，就不应该自由其他线程可以对资源进行读或写</span></span><br><span class="line"><span class="comment"> * 总结</span></span><br><span class="line"><span class="comment"> * 读读能共存</span></span><br><span class="line"><span class="comment"> * 读写不能共存</span></span><br><span class="line"><span class="comment"> * 写写不能共存</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ReadWriteLockDemo</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        MyCache myCache = <span class="keyword">new</span> MyCache();</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i &lt;= <span class="number">5</span>; i++) &#123;</span><br><span class="line">            <span class="keyword">final</span> <span class="keyword">int</span> tempInt = i;</span><br><span class="line">            <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">                myCache.put(tempInt + <span class="string">""</span>, tempInt + <span class="string">""</span>);</span><br><span class="line">            &#125;, <span class="string">"Thread "</span> + i).start();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i &lt;= <span class="number">5</span>; i++) &#123;</span><br><span class="line">            <span class="keyword">final</span> <span class="keyword">int</span> tempInt = i;</span><br><span class="line">            <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">                myCache.get(tempInt + <span class="string">""</span>);</span><br><span class="line">            &#125;, <span class="string">"Thread "</span> + i).start();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MyCache</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">volatile</span> Map&lt;String, Object&gt; map = <span class="keyword">new</span> HashMap&lt;&gt;();</span><br><span class="line">    <span class="keyword">private</span> ReentrantReadWriteLock rwLock = <span class="keyword">new</span> ReentrantReadWriteLock();</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 写操作：原子+独占</span></span><br><span class="line"><span class="comment">     * 整个过程必须是一个完整的统一体，中间不许被分割，不许被打断</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> value</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">put</span><span class="params">(String key, Object value)</span> </span>&#123;</span><br><span class="line">        rwLock.writeLock().lock();</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            System.out.println(Thread.currentThread().getName() + <span class="string">"\t正在写入："</span> + key);</span><br><span class="line">            TimeUnit.MILLISECONDS.sleep(<span class="number">300</span>);</span><br><span class="line">            map.put(key, value);</span><br><span class="line">            System.out.println(Thread.currentThread().getName() + <span class="string">"\t写入完成"</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            rwLock.writeLock().unlock();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">get</span><span class="params">(String key)</span> </span>&#123;</span><br><span class="line">        rwLock.readLock().lock();</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            System.out.println(Thread.currentThread().getName() + <span class="string">"\t正在读取："</span> + key);</span><br><span class="line">            TimeUnit.MILLISECONDS.sleep(<span class="number">300</span>);</span><br><span class="line">            Object result = map.get(key);</span><br><span class="line">            System.out.println(Thread.currentThread().getName() + <span class="string">"\t读取完成: "</span> + result);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            rwLock.readLock().unlock();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">clear</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        map.clear();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
</ol>
<h4 id="4、自旋锁"><a href="#4、自旋锁" class="headerlink" title="4、自旋锁"></a>4、自旋锁</h4><ol>
<li><p><strong>spinlock</strong></p>
<p>是指尝试获取锁的线程不会立即阻塞，而是==采用循环的方式去尝试获取锁==，这样的好处是减少线程上下文切换的消耗，缺点是循环会消耗CPU</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">int</span> <span class="title">getAndAddInt</span><span class="params">(Object var1, <span class="keyword">long</span> var2, <span class="keyword">int</span> var4)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">int</span> var5;</span><br><span class="line">    <span class="keyword">do</span> &#123;</span><br><span class="line">        var5 = <span class="keyword">this</span>.getIntVolatile(var1, var2);</span><br><span class="line">    &#125; <span class="keyword">while</span>(!<span class="keyword">this</span>.compareAndSwapInt(var1, var2, var5, var5 + var4));</span><br><span class="line">    <span class="keyword">return</span> var5;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>手写自旋锁：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.jian8.juc.lock;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.TimeUnit;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.atomic.AtomicReference;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 实现自旋锁</span></span><br><span class="line"><span class="comment"> * 自旋锁好处，循环比较获取知道成功位置，没有类似wait的阻塞</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * 通过CAS操作完成自旋锁，A线程先进来调用mylock方法自己持有锁5秒钟，B随后进来发现当前有线程持有锁，不是null，所以只能通过自旋等待，知道A释放锁后B随后抢到</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SpinLockDemo</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        SpinLockDemo spinLockDemo = <span class="keyword">new</span> SpinLockDemo();</span><br><span class="line">        <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">            spinLockDemo.mylock();</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                TimeUnit.SECONDS.sleep(<span class="number">3</span>);</span><br><span class="line">            &#125;<span class="keyword">catch</span> (Exception e)&#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">            spinLockDemo.myUnlock();</span><br><span class="line">        &#125;, <span class="string">"Thread 1"</span>).start();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            TimeUnit.SECONDS.sleep(<span class="number">3</span>);</span><br><span class="line">        &#125;<span class="keyword">catch</span> (Exception e)&#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">            spinLockDemo.mylock();</span><br><span class="line">            spinLockDemo.myUnlock();</span><br><span class="line">        &#125;, <span class="string">"Thread 2"</span>).start();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//原子引用线程</span></span><br><span class="line">    AtomicReference&lt;Thread&gt; atomicReference = <span class="keyword">new</span> AtomicReference&lt;&gt;();</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">mylock</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        Thread thread = Thread.currentThread();</span><br><span class="line">        System.out.println(Thread.currentThread().getName() + <span class="string">"\t come in"</span>);</span><br><span class="line">        <span class="keyword">while</span> (!atomicReference.compareAndSet(<span class="keyword">null</span>, thread)) &#123;</span><br><span class="line"></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">myUnlock</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        Thread thread = Thread.currentThread();</span><br><span class="line">        atomicReference.compareAndSet(thread, <span class="keyword">null</span>);</span><br><span class="line">        System.out.println(Thread.currentThread().getName()+<span class="string">"\t invoked myunlock()"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
</ol>
<h3 id="六、CountDownLatch-CyclicBarrier-Semaphore使用过吗"><a href="#六、CountDownLatch-CyclicBarrier-Semaphore使用过吗" class="headerlink" title="六、CountDownLatch/CyclicBarrier/Semaphore使用过吗"></a>六、CountDownLatch/CyclicBarrier/Semaphore使用过吗</h3><h4 id="1、CountDownLatch（火箭发射倒计时）"><a href="#1、CountDownLatch（火箭发射倒计时）" class="headerlink" title="1、CountDownLatch（火箭发射倒计时）"></a>1、CountDownLatch（火箭发射倒计时）</h4><ol>
<li><p>它允许一个或多个线程一直等待，知道其他线程的操作执行完后再执行。例如，应用程序的主线程希望在负责启动框架服务的线程已经启动所有的框架服务之后再执行</p>
</li>
<li><p>CountDownLatch主要有两个方法，当一个或多个线程调用await()方法时，调用线程会被阻塞。其他线程调用countDown()方法会将计数器减1，当计数器的值变为0时，因调用await()方法被阻塞的线程才会被唤醒，继续执行</p>
</li>
<li><p>代码示例：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.jian8.juc.conditionThread;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.CountDownLatch;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.TimeUnit;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CountDownLatchDemo</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> InterruptedException </span>&#123;</span><br><span class="line"><span class="comment">//        general();</span></span><br><span class="line">        countDownLatchTest();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">general</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i &lt;= <span class="number">6</span>; i++) &#123;</span><br><span class="line">            <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">                System.out.println(Thread.currentThread().getName()+<span class="string">"\t上完自习，离开教室"</span>);</span><br><span class="line">            &#125;, <span class="string">"Thread--&gt;"</span>+i).start();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">while</span> (Thread.activeCount()&gt;<span class="number">2</span>)&#123;</span><br><span class="line">            <span class="keyword">try</span> &#123; TimeUnit.SECONDS.sleep(<span class="number">2</span>); &#125; <span class="keyword">catch</span> (InterruptedException e) &#123; e.printStackTrace(); &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        System.out.println(Thread.currentThread().getName()+<span class="string">"\t=====班长最后关门走人"</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">countDownLatchTest</span><span class="params">()</span> <span class="keyword">throws</span> InterruptedException </span>&#123;</span><br><span class="line">        CountDownLatch countDownLatch = <span class="keyword">new</span> CountDownLatch(<span class="number">6</span>);</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i &lt;= <span class="number">6</span>; i++) &#123;</span><br><span class="line">            <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">                System.out.println(Thread.currentThread().getName()+<span class="string">"\t被灭"</span>);</span><br><span class="line">                countDownLatch.countDown();</span><br><span class="line">            &#125;, CountryEnum.forEach_CountryEnum(i).getRetMessage()).start();</span><br><span class="line">        &#125;</span><br><span class="line">        countDownLatch.await();</span><br><span class="line">        System.out.println(Thread.currentThread().getName()+<span class="string">"\t=====秦统一"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
</ol>
<h4 id="2、CyclicBarrier（集齐七颗龙珠召唤神龙）"><a href="#2、CyclicBarrier（集齐七颗龙珠召唤神龙）" class="headerlink" title="2、CyclicBarrier（集齐七颗龙珠召唤神龙）"></a>2、CyclicBarrier（集齐七颗龙珠召唤神龙）</h4><ol>
<li><p>CycliBarrier</p>
<p>可循环（Cyclic）使用的屏障。让一组线程到达一个屏障（也可叫同步点）时被阻塞，知道最后一个线程到达屏障时，屏障才会开门，所有被屏障拦截的线程才会继续干活，线程进入屏障通过CycliBarrier的await()方法</p>
</li>
<li><p>代码示例：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.jian8.juc.conditionThread;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.BrokenBarrierException;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.CyclicBarrier;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CyclicBarrierDemo</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        cyclicBarrierTest();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">cyclicBarrierTest</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        CyclicBarrier cyclicBarrier = <span class="keyword">new</span> CyclicBarrier(<span class="number">7</span>, () -&gt; &#123;</span><br><span class="line">            System.out.println(<span class="string">"====召唤神龙====="</span>);</span><br><span class="line">        &#125;);</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i &lt;= <span class="number">7</span>; i++) &#123;</span><br><span class="line">            <span class="keyword">final</span> <span class="keyword">int</span> tempInt = i;</span><br><span class="line">            <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">                System.out.println(Thread.currentThread().getName() + <span class="string">"\t收集到第"</span> + tempInt + <span class="string">"颗龙珠"</span>);</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    cyclicBarrier.await();</span><br><span class="line">                &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125; <span class="keyword">catch</span> (BrokenBarrierException e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;, <span class="string">""</span> + i).start();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
</ol>
<h4 id="3、Semaphore信号量"><a href="#3、Semaphore信号量" class="headerlink" title="3、Semaphore信号量"></a>3、Semaphore信号量</h4><p>可以代替Synchronize和Lock</p>
<ol>
<li><p><strong>信号量主要用于两个目的，一个是用于多个共享资源的互斥作用，另一个用于并发线程数的控制</strong></p>
</li>
<li><p>代码示例：</p>
<p><strong>抢车位示例</strong>：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line">package com.jian8.juc.conditionThread;</span><br><span class="line"></span><br><span class="line">import java.util.concurrent.Semaphore;</span><br><span class="line">import java.util.concurrent.TimeUnit;</span><br><span class="line"></span><br><span class="line">public class SemaphoreDemo &#123;</span><br><span class="line">    public static void main(String[] args) &#123;</span><br><span class="line">        Semaphore semaphore = new Semaphore(3);//模拟三个停车位</span><br><span class="line">        for (int i = 1; i &lt;= 6; i++) &#123;//模拟6部汽车</span><br><span class="line">            new Thread(() -&gt; &#123;</span><br><span class="line">                try &#123;</span><br><span class="line">                    semaphore.acquire();</span><br><span class="line">                    System.out.println(Thread.currentThread().getName() + &quot;\t抢到车位&quot;);</span><br><span class="line">                    try &#123;</span><br><span class="line">                        TimeUnit.SECONDS.sleep(3);//停车3s</span><br><span class="line">                    &#125; catch (InterruptedException e) &#123;</span><br><span class="line">                        e.printStackTrace();</span><br><span class="line">                    &#125;</span><br><span class="line">                    System.out.println(Thread.currentThread().getName() + &quot;\t停车3s后离开车位&quot;);</span><br><span class="line">                &#125; catch (InterruptedException e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125; finally &#123;</span><br><span class="line">                    semaphore.release();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;, &quot;Car &quot; + i).start();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
</ol>
<h3 id="七、阻塞队列"><a href="#七、阻塞队列" class="headerlink" title="七、阻塞队列"></a>七、阻塞队列</h3><ul>
<li><strong>==ArrayBlockingQueue==</strong>是一个基于数组结构的有界阻塞队列，此队列按FIFO原则对元素进行排序</li>
<li><strong>==LinkedBlockingQueue==</strong>是一个基于链表结构的阻塞队列，此队列按FIFO排序元素，吞吐量通常要高于ArrayBlockingQueue</li>
<li><strong>==SynchronousQueue==</strong>是一个不存储元素的阻塞队列，灭个插入操作必须等到另一个线程调用移除操作，否则插入操作一直处于阻塞状态，吞吐量通常要高于</li>
</ul>
<h4 id="1、队列和阻塞队列"><a href="#1、队列和阻塞队列" class="headerlink" title="1、队列和阻塞队列"></a>1、队列和阻塞队列</h4><ol>
<li><p>首先是一个队列，而一个阻塞队列再数据结构中所起的作用大致如下图</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">graph LR</span><br><span class="line">Thread1-- put --&gt;id1[&quot;阻塞队列&quot;]</span><br><span class="line">subgraph BlockingQueue</span><br><span class="line">	id1</span><br><span class="line">end</span><br><span class="line">id1-- Take --&gt;Thread2</span><br><span class="line">蛋糕师父--&quot;放(柜满阻塞)&quot;--&gt;id2[蛋糕展示柜]</span><br><span class="line">subgraph 柜</span><br><span class="line">	id2</span><br><span class="line">end</span><br><span class="line">id2--&quot;取(柜空阻塞)&quot;--&gt;顾客</span><br></pre></td></tr></table></figure>
<p>线程1往阻塞队列中添加元素，而线程2从阻塞队列中移除元素</p>
<p>当阻塞队列是空是，从队列中==获取==元素的操作会被阻塞</p>
<p>当阻塞队列是满时，从队列中==添加==元素的操作会被阻塞</p>
<p>试图从空的阻塞队列中获取元素的线程将会被阻塞，知道其他的线程网空的队列插入新的元素。</p>
<p>试图网已满的阻塞队列中添加新元素的线程同样会被阻塞，知道其他的线程从列中移除一个或者多个元素或者完全清空队列后使队列重新变得空闲起来并后续新增</p>
</li>
</ol>
<h4 id="2、为什么用？有什么好处？"><a href="#2、为什么用？有什么好处？" class="headerlink" title="2、为什么用？有什么好处？"></a>2、为什么用？有什么好处？</h4><ol>
<li><p>在多线程领域：所谓阻塞，在某些情况下会挂起线程，一旦满足条件，被挂起的线程又会自动被唤醒</p>
</li>
<li><p>为什么需要BlockingQueue</p>
<p>好处时我们不需要关心什么时候需要阻塞线程，什么时候需要唤醒线程，因为这一切BlockingQueue都给你一手包办了</p>
<p>在concurrent包发布以前，在多线程环境下，==我们每个程序员都必须自己控制这些细节，尤其还要兼顾效率和线程安全==，而这回给我们程序带来不小的复杂度</p>
</li>
</ol>
<h4 id="3、BlockingQueue的核心方法"><a href="#3、BlockingQueue的核心方法" class="headerlink" title="3、BlockingQueue的核心方法"></a>3、BlockingQueue的核心方法</h4><table>
<thead>
<tr>
<th>方法类型</th>
<th>抛出异常</th>
<th>特殊值</th>
<th>阻塞</th>
<th>超时</th>
</tr>
</thead>
<tbody>
<tr>
<td>插入</td>
<td>add(e)</td>
<td>offer(e)</td>
<td>put(e)</td>
<td>offer(e,time,unit)</td>
</tr>
<tr>
<td>移除</td>
<td>remove()</td>
<td>poll()</td>
<td>take</td>
<td>poll(time,unit)</td>
</tr>
<tr>
<td>检查</td>
<td>element()</td>
<td>peek()</td>
<td>不可用</td>
<td>不可用</td>
</tr>
</tbody>
</table>
<table>
<thead>
<tr>
<th>方法类型</th>
<th>status</th>
</tr>
</thead>
<tbody>
<tr>
<td>抛出异常</td>
<td>当阻塞队列满时，再往队列中add会抛<code>IllegalStateException: Queue full</code><br>当阻塞队列空时，在网队列里remove会抛<code>NoSuchElementException</code></td>
</tr>
<tr>
<td>特殊值</td>
<td>插入方法，成功true失败false<br>移除方法，成功返回出队列的元素，队列里没有就返回null</td>
</tr>
<tr>
<td>一直阻塞</td>
<td>当阻塞队列满时，生产者线程继续往队列里put元素，队列会一直阻塞线程知道put数据或响应中断退出<br>当阻塞队列空时，消费者线程试图从队列take元素，队列会一直阻塞消费者线程知道队列可用。</td>
</tr>
<tr>
<td>超时退出</td>
<td>当阻塞队列满时，队列会阻塞生产者线程一定时间，超过限时后生产者线程会退出</td>
</tr>
</tbody>
</table>
<h4 id="4、架构梳理-种类分析"><a href="#4、架构梳理-种类分析" class="headerlink" title="4、架构梳理+种类分析"></a>4、架构梳理+种类分析</h4><ol>
<li><p>种类分析</p>
<ul>
<li>==ArrayBlockingQueue==:由数据结构组成的有界阻塞队列。</li>
<li>==LinkedBlockingQueue==:由链表结构组成的有界（但大小默认值为<code>Integer.MAX_VALUE</code>)阻塞队列。</li>
<li>PriorityBlockingQueue:支持优先级排序的无界阻塞队列。</li>
<li>DelayQueue:使用优先级队列实现的延迟无界阻塞队列。</li>
<li>==SychronousQueue==:不存储元素的阻塞队列，也即单个元素的队列。</li>
<li>LinkedTransferQueue:由链表结构组成的无界阻塞队列。</li>
<li>LinkedBlocking<strong>Deque</strong>:由历览表结构组成的双向阻塞队列。</li>
</ul>
</li>
<li><p><strong>SychronousQueue</strong></p>
<ul>
<li><p>理论：SynchronousQueue没有容量，与其他BlockingQueue不同，SychronousQueue是一个不存储元素的BlockingQueue，每一个put操作必须要等待一个take操作，否则不能继续添加元素，反之亦然。</p>
</li>
<li><p>代码示例</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.jian8.juc.queue;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.BlockingQueue;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.SynchronousQueue;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.TimeUnit;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * ArrayBlockingQueue是一个基于数组结构的有界阻塞队列，此队列按FIFO原则对元素进行排序</span></span><br><span class="line"><span class="comment"> * LinkedBlockingQueue是一个基于链表结构的阻塞队列，此队列按FIFO排序元素，吞吐量通常要高于ArrayBlockingQueue</span></span><br><span class="line"><span class="comment"> * SynchronousQueue是一个不存储元素的阻塞队列，灭个插入操作必须等到另一个线程调用移除操作，否则插入操作一直处于阻塞状态，吞吐量通常要高于</span></span><br><span class="line"><span class="comment"> * 1.队列</span></span><br><span class="line"><span class="comment"> * 2.阻塞队列</span></span><br><span class="line"><span class="comment"> * 2.1 阻塞队列有没有好的一面</span></span><br><span class="line"><span class="comment"> * 2.2 不得不阻塞，你如何管理</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SynchronousQueueDemo</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> InterruptedException </span>&#123;</span><br><span class="line">        BlockingQueue&lt;String&gt; blockingQueue = <span class="keyword">new</span> SynchronousQueue&lt;&gt;();</span><br><span class="line">        <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                System.out.println(Thread.currentThread().getName() + <span class="string">"\t put 1"</span>);</span><br><span class="line">                blockingQueue.put(<span class="string">"1"</span>);</span><br><span class="line">                System.out.println(Thread.currentThread().getName() + <span class="string">"\t put 2"</span>);</span><br><span class="line">                blockingQueue.put(<span class="string">"2"</span>);</span><br><span class="line">                System.out.println(Thread.currentThread().getName() + <span class="string">"\t put 3"</span>);</span><br><span class="line">                blockingQueue.put(<span class="string">"3"</span>);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;, <span class="string">"AAA"</span>).start();</span><br><span class="line">        <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                TimeUnit.SECONDS.sleep(<span class="number">5</span>);</span><br><span class="line">                System.out.println(Thread.currentThread().getName() + <span class="string">"\ttake "</span> + blockingQueue.take());</span><br><span class="line">                TimeUnit.SECONDS.sleep(<span class="number">5</span>);</span><br><span class="line">                System.out.println(Thread.currentThread().getName() + <span class="string">"\ttake "</span> + blockingQueue.take());</span><br><span class="line">                TimeUnit.SECONDS.sleep(<span class="number">5</span>);</span><br><span class="line">                System.out.println(Thread.currentThread().getName() + <span class="string">"\ttake "</span> + blockingQueue.take());</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;, <span class="string">"BBB"</span>).start();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
</ul>
</li>
</ol>
<h4 id="5、用在哪里"><a href="#5、用在哪里" class="headerlink" title="5、用在哪里"></a>5、用在哪里</h4><ol>
<li><p>生产者消费者模式</p>
<ul>
<li><p>传统版</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.jian8.juc.queue;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.locks.Condition;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.locks.Lock;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.locks.ReentrantLock;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 一个初始值为零的变量，两个线程对其交替操作，一个加1一个减1，来5轮</span></span><br><span class="line"><span class="comment"> * 1. 线程  操作  资源类</span></span><br><span class="line"><span class="comment"> * 2. 判断  干活  通知</span></span><br><span class="line"><span class="comment"> * 3. 防止虚假唤起机制</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ProdConsumer_TraditionDemo</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        ShareData shareData = <span class="keyword">new</span> ShareData();</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i &lt;= <span class="number">5</span>; i++) &#123;</span><br><span class="line">            <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    shareData.increment();</span><br><span class="line">                &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;, <span class="string">"ProductorA "</span> + i).start();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i &lt;= <span class="number">5</span>; i++) &#123;</span><br><span class="line">            <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    shareData.decrement();</span><br><span class="line">                &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;, <span class="string">"ConsumerA  "</span> + i).start();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i &lt;= <span class="number">5</span>; i++) &#123;</span><br><span class="line">            <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    shareData.increment();</span><br><span class="line">                &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;, <span class="string">"ProductorB "</span> + i).start();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i &lt;= <span class="number">5</span>; i++) &#123;</span><br><span class="line">            <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    shareData.decrement();</span><br><span class="line">                &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;, <span class="string">"ConsumerB  "</span> + i).start();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ShareData</span> </span>&#123;<span class="comment">//资源类</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">int</span> number = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">private</span> Lock lock = <span class="keyword">new</span> ReentrantLock();</span><br><span class="line">    <span class="keyword">private</span> Condition condition = lock.newCondition();</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">increment</span><span class="params">()</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        lock.lock();</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="comment">//1.判断</span></span><br><span class="line">            <span class="keyword">while</span> (number != <span class="number">0</span>) &#123;</span><br><span class="line">                <span class="comment">//等待不能生产</span></span><br><span class="line">                condition.await();</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">//2.干活</span></span><br><span class="line">            number++;</span><br><span class="line">            System.out.println(Thread.currentThread().getName() + <span class="string">"\t"</span> + number);</span><br><span class="line">            <span class="comment">//3.通知</span></span><br><span class="line">            condition.signalAll();</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            lock.unlock();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">decrement</span><span class="params">()</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        lock.lock();</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="comment">//1.判断</span></span><br><span class="line">            <span class="keyword">while</span> (number == <span class="number">0</span>) &#123;</span><br><span class="line">                <span class="comment">//等待不能消费</span></span><br><span class="line">                condition.await();</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">//2.消费</span></span><br><span class="line">            number--;</span><br><span class="line">            System.out.println(Thread.currentThread().getName() + <span class="string">"\t"</span> + number);</span><br><span class="line">            <span class="comment">//3.通知</span></span><br><span class="line">            condition.signalAll();</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            lock.unlock();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
</ul>
</li>
</ol>
<ul>
<li><p>阻塞队列版</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.jian8.juc.queue;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.ArrayBlockingQueue;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.BlockingQueue;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.TimeUnit;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.atomic.AtomicInteger;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ProdConsumer_BlockQueueDemo</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        MyResource myResource = <span class="keyword">new</span> MyResource(<span class="keyword">new</span> ArrayBlockingQueue&lt;&gt;(<span class="number">10</span>));</span><br><span class="line">        <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">            System.out.println(Thread.currentThread().getName() + <span class="string">"\t生产线程启动"</span>);</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                myResource.myProd();</span><br><span class="line">            &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;, <span class="string">"Prod"</span>).start();</span><br><span class="line">        <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">            System.out.println(Thread.currentThread().getName() + <span class="string">"\t消费线程启动"</span>);</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                myResource.myConsumer();</span><br><span class="line">            &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;, <span class="string">"Consumer"</span>).start();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">try</span> &#123; TimeUnit.SECONDS.sleep(<span class="number">5</span>); &#125; <span class="keyword">catch</span> (InterruptedException e) &#123; e.printStackTrace(); &#125;</span><br><span class="line">        System.out.println(<span class="string">"5s后main叫停，线程结束"</span>);</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            myResource.stop();</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MyResource</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">volatile</span> <span class="keyword">boolean</span> flag = <span class="keyword">true</span>;<span class="comment">//默认开启，进行生产+消费</span></span><br><span class="line">    <span class="keyword">private</span> AtomicInteger atomicInteger = <span class="keyword">new</span> AtomicInteger();</span><br><span class="line"></span><br><span class="line">    BlockingQueue&lt;String&gt; blockingQueue = <span class="keyword">null</span>;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">MyResource</span><span class="params">(BlockingQueue&lt;String&gt; blockingQueue)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.blockingQueue = blockingQueue;</span><br><span class="line">        System.out.println(blockingQueue.getClass().getName());</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">myProd</span><span class="params">()</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        String data = <span class="keyword">null</span>;</span><br><span class="line">        <span class="keyword">boolean</span> retValue;</span><br><span class="line">        <span class="keyword">while</span> (flag) &#123;</span><br><span class="line">            data = atomicInteger.incrementAndGet() + <span class="string">""</span>;</span><br><span class="line">            retValue = blockingQueue.offer(data, <span class="number">2</span>, TimeUnit.SECONDS);</span><br><span class="line">            <span class="keyword">if</span> (retValue) &#123;</span><br><span class="line">                System.out.println(Thread.currentThread().getName() + <span class="string">"\t插入队列"</span> + data + <span class="string">"成功"</span>);</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                System.out.println(Thread.currentThread().getName() + <span class="string">"\t插入队列"</span> + data + <span class="string">"失败"</span>);</span><br><span class="line">            &#125;</span><br><span class="line">            TimeUnit.SECONDS.sleep(<span class="number">1</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        System.out.println(Thread.currentThread().getName() + <span class="string">"\t大老板叫停了，flag=false，生产结束"</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">myConsumer</span><span class="params">()</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        String result = <span class="keyword">null</span>;</span><br><span class="line">        <span class="keyword">while</span> (flag) &#123;</span><br><span class="line">            result = blockingQueue.poll(<span class="number">2</span>, TimeUnit.SECONDS);</span><br><span class="line">            <span class="keyword">if</span> (<span class="keyword">null</span> == result || result.equalsIgnoreCase(<span class="string">""</span>)) &#123;</span><br><span class="line">                flag = <span class="keyword">false</span>;</span><br><span class="line">                System.out.println(Thread.currentThread().getName() + <span class="string">"\t超过2s没有取到蛋糕，消费退出"</span>);</span><br><span class="line">                System.out.println();</span><br><span class="line">                <span class="keyword">return</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            System.out.println(Thread.currentThread().getName() + <span class="string">"\t消费队列"</span> + result + <span class="string">"成功"</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">stop</span><span class="params">()</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        flag = <span class="keyword">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
</ul>
<ol start="2">
<li><p>线程池</p>
</li>
<li><p>消息中间件</p>
</li>
</ol>
<h4 id="6、synchronized和lock有什么区别？用新的lock有什么好处？请举例"><a href="#6、synchronized和lock有什么区别？用新的lock有什么好处？请举例" class="headerlink" title="6、synchronized和lock有什么区别？用新的lock有什么好处？请举例"></a>6、synchronized和lock有什么区别？用新的lock有什么好处？请举例</h4><blockquote>
<p>区别</p>
</blockquote>
<ol>
<li><p>原始构成</p>
<ul>
<li><p>synchronized时关键字属于jvm</p>
<p><strong>monitorenter</strong>，底层是通过monitor对象来完成，其实wait/notify等方法也依赖于monitor对象只有在同步或方法中才能掉wait/notify等方法</p>
<p><strong>monitorexit</strong></p>
</li>
<li><p>Lock是具体类，是api层面的锁（java.util.）</p>
</li>
</ul>
</li>
<li><p>使用方法</p>
<ul>
<li>sychronized不需要用户取手动释放锁，当synchronized代码执行完后系统会自动让线程释放对锁的占用</li>
<li>ReentrantLock则需要用户去手动释放锁若没有主动释放锁，就有可能导致出现死锁现象，需要lock()和unlock()方法配合try/finally语句块来完成</li>
</ul>
</li>
<li><p>等待是否可中断</p>
<ul>
<li>synchronized不可中断，除非抛出异常或者正常运行完成</li>
<li>ReentrantLock可中断，设置超时方法tryLock(long timeout, TimeUnit unit)，或者lockInterruptibly()放代码块中，调用interrupt()方法可中断。</li>
</ul>
</li>
<li><p>加锁是否公平</p>
<ul>
<li>synchronized非公平锁</li>
<li>ReentrantLock两者都可以，默认公平锁，构造方法可以传入boolean值，true为公平锁，false为非公平锁</li>
</ul>
</li>
<li><p>锁绑定多个条件Condition</p>
<ul>
<li>synchronized没有</li>
<li>ReentrantLock用来实现分组唤醒需要要唤醒的线程们，可以精确唤醒，而不是像synchronized要么随机唤醒一个线程要么唤醒全部线程。</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.jian8.juc.lock;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.locks.Condition;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.locks.Lock;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.locks.ReentrantLock;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * synchronized和lock区别</span></span><br><span class="line"><span class="comment"> * &lt;p===lock可绑定多个条件===</span></span><br><span class="line"><span class="comment"> * 对线程之间按顺序调用，实现A&gt;B&gt;C三个线程启动，要求如下：</span></span><br><span class="line"><span class="comment"> * AA打印5次，BB打印10次，CC打印15次</span></span><br><span class="line"><span class="comment"> * 紧接着</span></span><br><span class="line"><span class="comment"> * AA打印5次，BB打印10次，CC打印15次</span></span><br><span class="line"><span class="comment"> * 。。。。</span></span><br><span class="line"><span class="comment"> * 来十轮</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SyncAndReentrantLockDemo</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        ShareData shareData = <span class="keyword">new</span> ShareData();</span><br><span class="line">        <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i &lt;= <span class="number">10</span>; i++) &#123;</span><br><span class="line">                shareData.print5();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;, <span class="string">"A"</span>).start();</span><br><span class="line">        <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i &lt;= <span class="number">10</span>; i++) &#123;</span><br><span class="line">                shareData.print10();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;, <span class="string">"B"</span>).start();</span><br><span class="line">        <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i &lt;= <span class="number">10</span>; i++) &#123;</span><br><span class="line">                shareData.print15();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;, <span class="string">"C"</span>).start();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ShareData</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">int</span> number = <span class="number">1</span>;<span class="comment">//A:1 B:2 C:3</span></span><br><span class="line">    <span class="keyword">private</span> Lock lock = <span class="keyword">new</span> ReentrantLock();</span><br><span class="line">    <span class="keyword">private</span> Condition condition1 = lock.newCondition();</span><br><span class="line">    <span class="keyword">private</span> Condition condition2 = lock.newCondition();</span><br><span class="line">    <span class="keyword">private</span> Condition condition3 = lock.newCondition();</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">print5</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        lock.lock();</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="comment">//判断</span></span><br><span class="line">            <span class="keyword">while</span> (number != <span class="number">1</span>) &#123;</span><br><span class="line">                condition1.await();</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">//干活</span></span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i &lt;= <span class="number">5</span>; i++) &#123;</span><br><span class="line">                System.out.println(Thread.currentThread().getName() + <span class="string">"\t"</span> + i);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">//通知</span></span><br><span class="line">            number = <span class="number">2</span>;</span><br><span class="line">            condition2.signal();</span><br><span class="line"></span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            lock.unlock();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">print10</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        lock.lock();</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="comment">//判断</span></span><br><span class="line">            <span class="keyword">while</span> (number != <span class="number">2</span>) &#123;</span><br><span class="line">                condition2.await();</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">//干活</span></span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i &lt;= <span class="number">10</span>; i++) &#123;</span><br><span class="line">                System.out.println(Thread.currentThread().getName() + <span class="string">"\t"</span> + i);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">//通知</span></span><br><span class="line">            number = <span class="number">3</span>;</span><br><span class="line">            condition3.signal();</span><br><span class="line"></span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            lock.unlock();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">print15</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        lock.lock();</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="comment">//判断</span></span><br><span class="line">            <span class="keyword">while</span> (number != <span class="number">3</span>) &#123;</span><br><span class="line">                condition3.await();</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">//干活</span></span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i &lt;= <span class="number">15</span>; i++) &#123;</span><br><span class="line">                System.out.println(Thread.currentThread().getName() + <span class="string">"\t"</span> + i);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">//通知</span></span><br><span class="line">            number = <span class="number">1</span>;</span><br><span class="line">            condition1.signal();</span><br><span class="line"></span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            lock.unlock();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
</ol>
<h3 id="八、线程池用过吗？ThreadPoolExecutor谈谈你的理解"><a href="#八、线程池用过吗？ThreadPoolExecutor谈谈你的理解" class="headerlink" title="八、线程池用过吗？ThreadPoolExecutor谈谈你的理解"></a>八、线程池用过吗？ThreadPoolExecutor谈谈你的理解</h3><h4 id="1、Callable接口的使用"><a href="#1、Callable接口的使用" class="headerlink" title="1、Callable接口的使用"></a>1、Callable接口的使用</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.jian8.juc.thread;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.Callable;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.ExecutionException;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.FutureTask;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.TimeUnit;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 多线程中，第三种获得多线程的方式</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CallableDemo</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> ExecutionException, InterruptedException </span>&#123;</span><br><span class="line">        <span class="comment">//FutureTask(Callable&lt;V&gt; callable)</span></span><br><span class="line">        FutureTask&lt;Integer&gt; futureTask = <span class="keyword">new</span> FutureTask&lt;Integer&gt;(<span class="keyword">new</span> MyThread2());</span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Thread(futureTask, <span class="string">"AAA"</span>).start();</span><br><span class="line"><span class="comment">//        new Thread(futureTask, "BBB").start();//复用，直接取值，不要重启两个线程</span></span><br><span class="line">        <span class="keyword">int</span> a = <span class="number">100</span>;</span><br><span class="line">        <span class="keyword">int</span> b = <span class="number">0</span>;</span><br><span class="line">        <span class="comment">//b = futureTask.get();//要求获得Callable线程的计算结果，如果没有计算完成就要去强求，会导致堵塞，直到计算完成</span></span><br><span class="line">        <span class="keyword">while</span> (!futureTask.isDone()) &#123;<span class="comment">//当futureTask完成后取值</span></span><br><span class="line">            b = futureTask.get();</span><br><span class="line">        &#125;</span><br><span class="line">        System.out.println(<span class="string">"*******Result"</span> + (a + b));</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MyThread</span> <span class="keyword">implements</span> <span class="title">Runnable</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MyThread2</span> <span class="keyword">implements</span> <span class="title">Callable</span>&lt;<span class="title">Integer</span>&gt; </span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Integer <span class="title">call</span><span class="params">()</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">"Callable come in"</span>);</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            TimeUnit.SECONDS.sleep(<span class="number">5</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="number">1024</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="2、为什么使用线程池"><a href="#2、为什么使用线程池" class="headerlink" title="2、为什么使用线程池"></a>2、为什么使用线程池</h4><ol>
<li><p>线程池做的工作主要是控制运行的线程的数量，处理过程中将任务放入队列，然后在线程创建后启动给这些任务，如果线程数量超过了最大数量，超出数量的线程排队等候，等其他线程执行完毕，再从队列中取出任务来执行</p>
</li>
<li><p>主要特点</p>
<p>线程复用、控制最大并发数、管理线程</p>
<ul>
<li>降低资源消耗，通过重复利用已创建的线程降低线程创建和销毁造成的消耗</li>
<li>提过响应速度。当任务到达时，任务可以不需要等到线程创建就能立即执行</li>
<li>提高线程的客观理想。线程是稀缺资源，如果无限制的创建，不仅会消耗系统资源，还会降低系统的稳定性，使用线程池可以进行统一的分配，调优和监控</li>
</ul>
</li>
</ol>
<h4 id="3、线程池如何使用"><a href="#3、线程池如何使用" class="headerlink" title="3、线程池如何使用"></a>3、线程池如何使用</h4><ol>
<li><p>架构说明</p>
<p>Java中的线程池是通过Executor框架实现的，该框架中用到了Executor,Executors,ExecutorService,ThreadPoolExecutor</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">graph BT</span><br><span class="line">	类-Executors</span><br><span class="line">	类-ScheduledThreadPoolExecutor--&gt;类-ThreadPoolExecutor</span><br><span class="line">	类-ThreadPoolExecutor--&gt;类-AbstractExecutorService</span><br><span class="line">	类-AbstractExecutorService-.-&gt;接口-ExecutorService</span><br><span class="line">	类-ScheduledThreadPoolExecutor-.-&gt;接口-ScheduledExecutorService</span><br><span class="line">	接口-ScheduledExecutorService--&gt;接口-ExecutorService</span><br><span class="line">	接口-ExecutorService--&gt;接口-Executor</span><br></pre></td></tr></table></figure>
</li>
<li><p>编码实现</p>
<p>实现有五种，Executors.newScheduledThreadPool()是带时间调度的，java8新推出Executors.newWorkStealingPool(int),使用目前机器上可用的处理器作为他的并行级别</p>
<p>重点有三种</p>
<ul>
<li><p>Executors.newFixedThreadPool(int) </p>
<p><strong>执行长期的任务，性能好很多</strong></p>
<p>创建一个定长线程池，可控制线程最大并发数，炒出的线程回在队列中等待。</p>
<p>newFixedThreadPool创建的线程池corePoolSize和maximumPoolSize值是想到等的，他使用的是LinkedBlockingQueue</p>
</li>
<li><p>Executors.newSingleThreadExecutor()</p>
<p><strong>一个任务一个任务执行的场景</strong></p>
<p>创建一个单线程话的线程池，他只会用唯一的工作线程来执行任务，保证所有任务按照指定顺序执行</p>
<p>newSingleThreadExecutor将corePoolSize和maximumPoolSize都设置为1，使用LinkedBlockingQueue</p>
</li>
<li><p>Executors.newCachedThreadPool() </p>
<p><strong>执行很多短期异步的小程序或负载较轻的服务器</strong></p>
<p>创建一个可缓存线程池，如果线程池长度超过处理需要，可灵活回收空闲县城，若无可回收，则新建线程。</p>
<p>newCachedThreadPool将corePoolSize设置为0，将maximumPoolSize设置为Integer.MAX_VALUE,使用的SynchronousQueue,也就是说来了任务就创建线程运行，当县城空闲超过60s，就销毁线程</p>
</li>
</ul>
</li>
<li><p><strong>ThreadPoolExecutor</strong></p>
</li>
</ol>
<h4 id="4、线程池的几个重要参数介绍"><a href="#4、线程池的几个重要参数介绍" class="headerlink" title="4、线程池的几个重要参数介绍"></a>4、线程池的几个重要参数介绍</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">public ThreadPoolExecutor(int corePoolSize,</span><br><span class="line">                          int maximumPoolSize,</span><br><span class="line">                          long keepAliveTime,</span><br><span class="line">                          TimeUnit unit,</span><br><span class="line">                          BlockingQueue&lt;Runnable&gt; workQueue,</span><br><span class="line">                          ThreadFactory threadFactory,</span><br><span class="line">                          RejectedExecutionHandler handler)</span><br></pre></td></tr></table></figure>
<ol>
<li><strong>==corePoolSize==</strong>：线程池中常驻核心线程数<ul>
<li>在创建了线程池后，当有请求任务来之后，就会安排池中的线程去执行请求任务</li>
<li>当线程池的线程数达到corePoolSize后，就会把到达的任务放到缓存队列当中</li>
</ul>
</li>
<li><strong>==maximumPoolSize==</strong>：线程池能够容纳同时执行的最大线程数，必须大于等于1</li>
<li><strong>==keepAliveTime==</strong>：多余的空闲线程的存活时间<ul>
<li>当前线程池数量超过corePoolSize时，档口空闲时间达到keepAliveTime值时，多余空闲线程会被销毁到只剩下corePoolSize个线程为止</li>
</ul>
</li>
<li><strong>==unit==</strong>：keepAliveTime的单位</li>
<li><strong>==workQueue==</strong>：任务队列，被提交但尚未被执行的任务</li>
<li><strong>==threadFactory==</strong>：表示生成线程池中工作线程的线程工厂，用于创建线程一般用默认的即可</li>
<li><strong>==handler==</strong>：拒绝策略，表示当队列满了并且工作线程大于等于线程池的最大线程数（maximumPoolSize）时如何来拒绝请求执行的runable的策略</li>
</ol>
<h4 id="5、线程池的底层工作原理"><a href="#5、线程池的底层工作原理" class="headerlink" title="5、线程池的底层工作原理"></a>5、线程池的底层工作原理</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">graph LR</span><br><span class="line">subgraph 使用者</span><br><span class="line">main(提交任务)</span><br><span class="line">end</span><br><span class="line">main--&gt;core&#123;核心线程是否已满&#125;</span><br><span class="line">subgraph 线程池</span><br><span class="line">core--是--&gt;queue&#123;队列是否已满&#125;</span><br><span class="line">queue--是--&gt;pool&#123;线程池是否已满&#125;</span><br><span class="line">pool--是--&gt;reject[&quot;按照拒绝策略处理&lt;br&gt;无法执行的任务&quot;]</span><br><span class="line">core--否--&gt;id[创建线程执行任务]</span><br><span class="line">queue--否--&gt;任务入队列等待</span><br><span class="line">pool--否--&gt;创建线程执行任务</span><br><span class="line">end</span><br></pre></td></tr></table></figure>
<p><strong>==流程==</strong></p>
<ol>
<li><p>在创建了线程池之后，等待提交过来的 人物请求。</p>
</li>
<li><p>当调用execute()方法添加一个请求任务时，线程池会做出如下判断</p>
<p>2.1 如果正在运行的线程数量小于corePoolSize，那么马上船舰线程运行这个任务；</p>
<p>2.2 如果正在运行的线程数量大于或等于corePoolSize，那么将这个任务放入队列；</p>
<p>2.3如果此时队列满了且运行的线程数小于maximumPoolSize，那么还是要创建非核心线程立刻运行此任务</p>
<p>2.4如果队列满了且正在运行的线程数量大于或等于maxmumPoolSize，那么启动饱和拒绝策略来执行</p>
</li>
<li><p>当一个线程完成任务时，他会从队列中却下一个任务来执行</p>
</li>
<li><p>当一个线程无事可做超过一定的时间（keepAliveTime）时，线程池会判断：</p>
<p>如果当前运行的线程数大于corePoolSize，那么这个线程会被停掉；所以线程池的所有任务完成后他最大会收缩到corePoolSize的大小</p>
</li>
</ol>
<h3 id="九、线程池用过吗？生产上你如何设置合理参数"><a href="#九、线程池用过吗？生产上你如何设置合理参数" class="headerlink" title="九、线程池用过吗？生产上你如何设置合理参数"></a>九、线程池用过吗？生产上你如何设置合理参数</h3><h4 id="1、线程池的拒绝策略"><a href="#1、线程池的拒绝策略" class="headerlink" title="1、线程池的拒绝策略"></a>1、线程池的拒绝策略</h4><ol>
<li><p>什么是线程策略</p>
<p>等待队列也已经排满了，再也塞不下新任务了，同时线程池中的max线程也达到了，无法继续为新任务服务。这时我们就需要拒绝策略机制合理的处理这个问题。</p>
</li>
<li><p>JDK内置的拒绝策略</p>
<ul>
<li><p>AbortPolicy(默认)</p>
<p>直接抛出RejectedExecutionException异常阻止系统正常运行</p>
</li>
<li><p>CallerRunsPolicy</p>
<p>”调用者运行“一种调节机制，该策略既不会抛弃任务，也不会抛出异常，而是将某些任务回退到调用者，从而降低新任务的流量</p>
</li>
<li><p>DiscardOldestPolicy</p>
<p>抛弃队列中等待最久的任务，然后把当前任务加入队列中尝试再次提交当前任务</p>
</li>
<li><p>DiscardPolicy</p>
<p>直接丢弃任务，不予任何处理也不抛异常。如果允许任务丢失，这是最好的一种方案</p>
</li>
</ul>
</li>
<li><p>均实现了RejectedExecutionHandler接口</p>
</li>
</ol>
<h4 id="2、你在工作中单一的-固定数的-可变的三种创建线程池的方法，用哪个多"><a href="#2、你在工作中单一的-固定数的-可变的三种创建线程池的方法，用哪个多" class="headerlink" title="2、你在工作中单一的/固定数的/可变的三种创建线程池的方法，用哪个多"></a>2、你在工作中单一的/固定数的/可变的三种创建线程池的方法，用哪个多</h4><p><strong>==一个都不用，我们生产上只能使用自定义的！！！！==</strong></p>
<p>为什么？</p>
<p>线程池不允许使用Executors创建，试试通过ThreadPoolExecutor的方式，规避资源耗尽风险</p>
<p>FixedThreadPool和SingleThreadPool允许请求队列长度为Integer.MAX_VALUE，可能会堆积大量请求；；CachedThreadPool和ScheduledThreadPool允许的创建线程数量为Integer.MAX_VALUE，可能会创建大量线程，导致OOM</p>
<h4 id="3、你在工作中时如何使用线程池的，是否自定义过线程池使用"><a href="#3、你在工作中时如何使用线程池的，是否自定义过线程池使用" class="headerlink" title="3、你在工作中时如何使用线程池的，是否自定义过线程池使用"></a>3、你在工作中时如何使用线程池的，是否自定义过线程池使用</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.jian8.juc.thread;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.*;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 第四种获得java多线程的方式--线程池</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MyThreadPoolDemo</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        ExecutorService threadPool = <span class="keyword">new</span> ThreadPoolExecutor(<span class="number">3</span>, <span class="number">5</span>, <span class="number">1L</span>,</span><br><span class="line">                							TimeUnit.SECONDS,</span><br><span class="line">                							<span class="keyword">new</span> LinkedBlockingDeque&lt;&gt;(<span class="number">3</span>),</span><br><span class="line">                                            Executors.defaultThreadFactory(), </span><br><span class="line">                                            <span class="keyword">new</span> ThreadPoolExecutor.DiscardPolicy());</span><br><span class="line"><span class="comment">//new ThreadPoolExecutor.AbortPolicy();</span></span><br><span class="line"><span class="comment">//new ThreadPoolExecutor.CallerRunsPolicy();</span></span><br><span class="line"><span class="comment">//new ThreadPoolExecutor.DiscardOldestPolicy();</span></span><br><span class="line"><span class="comment">//new ThreadPoolExecutor.DiscardPolicy();</span></span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i &lt;= <span class="number">10</span>; i++) &#123;</span><br><span class="line">                threadPool.execute(() -&gt; &#123;</span><br><span class="line">                    System.out.println(Thread.currentThread().getName() + <span class="string">"\t办理业务"</span>);</span><br><span class="line">                &#125;);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            threadPool.shutdown();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="4、合理配置线程池你是如何考虑的？"><a href="#4、合理配置线程池你是如何考虑的？" class="headerlink" title="4、合理配置线程池你是如何考虑的？"></a>4、合理配置线程池你是如何考虑的？</h4><ol>
<li><p><strong>CPU密集型</strong></p>
<p>CPU密集的意思是该任务需要大量的运算，而没有阻塞，CPU一直全速运行</p>
<p>CPU密集任务只有在真正多核CPU上才可能得到加速（通过多线程）</p>
<p>而在单核CPU上，无论你开几个模拟的多线程该任务都不可能得到加速，因为CPU总的运算能力就那些</p>
<p>CPU密集型任务配置尽可能少的线程数量：</p>
<p>==<strong>一般公式：CPU核数+1个线程的线程池</strong>==</p>
</li>
<li><p><strong>IO密集型</strong></p>
<ul>
<li><p>由于IO密集型任务线程并不是一直在执行任务，则应配置经可能多的线程，如CPU核数 * 2</p>
</li>
<li><p>IO密集型，即该任务需要大量的IO，即大量的阻塞。</p>
<p>在单线程上运行IO密集型的任务会导致浪费大量的 CPU运算能力浪费在等待。</p>
<p>所以在IO密集型任务中使用多线程可以大大的加速程序运行，即使在单核CPU上，这种加速主要就是利用了被浪费掉的阻塞时间。</p>
<p>IO密集型时，大部分线程都阻塞，故需要多配置线程数：</p>
<p>参考公式：==CPU核数/（1-阻塞系数） 阻塞系数在0.8~0.9之间==</p>
<p>八核CPU：8/（1-0，9）=80</p>
</li>
</ul>
</li>
</ol>
<h3 id="十、死锁编码及定位分析"><a href="#十、死锁编码及定位分析" class="headerlink" title="十、死锁编码及定位分析"></a>十、死锁编码及定位分析</h3><ol>
<li><p>是什么</p>
<p>死锁是指两个或两个以上的进程在执行过程中，因争夺资源而造成的一种互相等待的现象，若无外力干涉那他们都将无法推进下去，如果系统资源充足，进程的资源请求都能够得到满足，死锁出现的可能性就很低，否则就会因争夺有限的资源而陷入死锁。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">graph TD</span><br><span class="line"> threadA(线程A)</span><br><span class="line"> threadB(线程B)</span><br><span class="line"> lockA((锁A))</span><br><span class="line"> lockB((锁B))</span><br><span class="line"> threadA--持有--&gt;lockA</span><br><span class="line"> threadB--试图获取--&gt;lockA</span><br><span class="line"> threadB--持有--&gt;lockB</span><br><span class="line"> threadA--试图获取--&gt;lockB</span><br></pre></td></tr></table></figure>
</li>
<li><p>产生死锁的主要原因</p>
<ul>
<li>系统资源不足</li>
<li>进程运行推进的顺序不合适</li>
<li>资源分配不当</li>
</ul>
</li>
<li><p>死锁示例</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.jian8.juc.thread;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.TimeUnit;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 死锁是指两个或两个以上的进程在执行过程中，因争夺资源而造成的一种互相等待的现象，若无外力干涉那他们都将无法推进下去，</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DeadLockDemo</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        String lockA = <span class="string">"lockA"</span>;</span><br><span class="line">        String lockB = <span class="string">"lockB"</span>;</span><br><span class="line">        <span class="keyword">new</span> Thread(<span class="keyword">new</span> HoldThread(lockA,lockB),<span class="string">"Thread-AAA"</span>).start();</span><br><span class="line">        <span class="keyword">new</span> Thread(<span class="keyword">new</span> HoldThread(lockB,lockA),<span class="string">"Thread-BBB"</span>).start();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">HoldThread</span> <span class="keyword">implements</span> <span class="title">Runnable</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> String lockA;</span><br><span class="line">    <span class="keyword">private</span> String lockB;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">HoldThread</span><span class="params">(String lockA, String lockB)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.lockA = lockA;</span><br><span class="line">        <span class="keyword">this</span>.lockB = lockB;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">synchronized</span> (lockA) &#123;</span><br><span class="line">            System.out.println(Thread.currentThread().getName() + <span class="string">"\t自己持有："</span> + lockA + <span class="string">"\t尝试获得："</span> + lockB);</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                TimeUnit.SECONDS.sleep(<span class="number">2</span>);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">synchronized</span> (lockB) &#123;</span><br><span class="line">                System.out.println(Thread.currentThread().getName() + <span class="string">"\t自己持有："</span> + lockB + <span class="string">"\t尝试获得："</span> + lockA);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
<li><p>解决</p>
<ol>
<li>使用<code>jps -l</code>定位进程号</li>
<li><code>jstack 进程号</code>找到死锁查看</li>
<li><code>jconsole</code> 可视化工具</li>
</ol>
</li>
</ol>

        </div>

        <blockquote class="post-copyright">
    
    <div class="content">
        
<span class="post-time">
    最后更新时间：<time datetime="2020-04-17T05:33:14.326Z" itemprop="dateUpdated">2020-04-17 13:33:14</time>
</span><br>


        
    </div>
    
    <footer>
        <a href="http://springcloud.xn--ses554g">
            <img src="/img/123.png" alt="Edward">
            Edward
        </a>
    </footer>
</blockquote>

        


        <div class="post-footer">
            
	<ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/juc/">juc</a></li></ul>


            
<div class="page-share-wrap">
    

<div class="page-share" id="pageShare">
    <ul class="reset share-icons">
      <li>
        <a class="weibo share-sns" target="_blank" href="http://service.weibo.com/share/share.php?url=http://springcloud.xn--ses554g/2020/04/13/JUC多线程及高并发/&title=《周阳-阳哥JUC多线程及高并发部分》 — Edward&pic=http://springcloud.xn--ses554g/img/123.png" data-title="微博">
          <i class="icon icon-weibo"></i>
        </a>
      </li>
      <li>
        <a class="weixin share-sns wxFab" href="javascript:;" data-title="微信">
          <i class="icon icon-weixin"></i>
        </a>
      </li>
      <li>
        <a class="qq share-sns" target="_blank" href="http://connect.qq.com/widget/shareqq/index.html?url=http://springcloud.xn--ses554g/2020/04/13/JUC多线程及高并发/&title=《周阳-阳哥JUC多线程及高并发部分》 — Edward&source=" data-title=" QQ">
          <i class="icon icon-qq"></i>
        </a>
      </li>
      <li>
        <a class="facebook share-sns" target="_blank" href="https://www.facebook.com/sharer/sharer.php?u=http://springcloud.xn--ses554g/2020/04/13/JUC多线程及高并发/" data-title=" Facebook">
          <i class="icon icon-facebook"></i>
        </a>
      </li>
      <li>
        <a class="twitter share-sns" target="_blank" href="https://twitter.com/intent/tweet?text=《周阳-阳哥JUC多线程及高并发部分》 — Edward&url=http://springcloud.xn--ses554g/2020/04/13/JUC多线程及高并发/&via=http://springcloud.xn--ses554g" data-title=" Twitter">
          <i class="icon icon-twitter"></i>
        </a>
      </li>
      <li>
        <a class="google share-sns" target="_blank" href="https://plus.google.com/share?url=http://springcloud.xn--ses554g/2020/04/13/JUC多线程及高并发/" data-title=" Google+">
          <i class="icon icon-google-plus"></i>
        </a>
      </li>
    </ul>
 </div>



    <a href="javascript:;" id="shareFab" class="page-share-fab waves-effect waves-circle">
        <i class="icon icon-share-alt icon-lg"></i>
    </a>
</div>



        </div>
    </div>

    
<nav class="post-nav flex-row flex-justify-between flex-row-reverse">
  

  
    <div class="waves-block waves-effect next">
      <a href="/2020/04/13/JVM面试/" id="post-next" class="post-nav-link">
        <div class="tips">Next <i class="icon icon-angle-right icon-lg icon-pl"></i></div>
        <h4 class="title">周阳-阳哥JVM面试部分</h4>
      </a>
    </div>
  
</nav>



    











    <!-- Valine Comments -->
    <div class="comments vcomment" id="comments"></div>
    <script src="//cdn1.lncld.net/static/js/3.0.4/av-min.js"></script>
    <script src="//unpkg.com/valine@latest/dist/Valine.min.js"></script>
    <!-- Valine Comments script -->
    <script>
        var GUEST_INFO = ['nick','mail','link'];
        var guest_info = 'nick,mail,link'.split(',').filter(function(item){
          return GUEST_INFO.indexOf(item) > -1
        });
        new Valine({
            el: '#comments',
            notify: 'false' == 'true',
            verify: 'false' == 'true',
            appId: "NHOU6qcrdobSwD5wwUJJ31pQ-gzGzoHsz",
            appKey: "E0RJgPMPwkjfMBOA88EalSzJ",
            avatar: "mm",
            placeholder: "Just go go",
            guest_info: guest_info.length == 0 ? GUEST_INFO : guest_info,
            pageSize: "10"
        })
    </script>
    <!-- Valine Comments end -->







</article>



</div>

        <footer class="footer">
    <div class="top">
        <p>
    <span id="busuanzi_container_site_uv">
        站点总访客数：30<span id="busuanzi_value_site_uv"></span>
    </span>
    <span id="busuanzi_container_site_pv">
        站点总访问量：425<span id="busuanzi_value_site_pv"></span>
    </span>
</p>


        <p>
            
                <span><a href="/atom.xml" target="_blank" class="rss" title="rss"><i class="icon icon-lg icon-rss"></i></a></span>
            
            <span>博客内容遵循 <a rel="license" href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh">知识共享 署名 - 非商业性 - 相同方式共享 4.0 国际协议</a></span>
        </p>
    </div>
    <div class="bottom">
        <p><span>Edward &copy; 2017 - 2021</span>
            <span>
                
                Power by <a href="http://hexo.io/" target="_blank">Hexo</a> Theme <a href="https://github.com/yscoder/hexo-theme-indigo" target="_blank">indigo</a>
            </span>
        </p>
    </div>
</footer>

    </main>
    <div class="mask" id="mask"></div>
<a href="javascript:;" id="gotop" class="waves-effect waves-circle waves-light"><span class="icon icon-lg icon-chevron-up"></span></a>



<div class="global-share" id="globalShare">
    <ul class="reset share-icons">
      <li>
        <a class="weibo share-sns" target="_blank" href="http://service.weibo.com/share/share.php?url=http://springcloud.xn--ses554g/2020/04/13/JUC多线程及高并发/&title=《周阳-阳哥JUC多线程及高并发部分》 — Edward&pic=http://springcloud.xn--ses554g/img/123.png" data-title="微博">
          <i class="icon icon-weibo"></i>
        </a>
      </li>
      <li>
        <a class="weixin share-sns wxFab" href="javascript:;" data-title="微信">
          <i class="icon icon-weixin"></i>
        </a>
      </li>
      <li>
        <a class="qq share-sns" target="_blank" href="http://connect.qq.com/widget/shareqq/index.html?url=http://springcloud.xn--ses554g/2020/04/13/JUC多线程及高并发/&title=《周阳-阳哥JUC多线程及高并发部分》 — Edward&source=" data-title=" QQ">
          <i class="icon icon-qq"></i>
        </a>
      </li>
      <li>
        <a class="facebook share-sns" target="_blank" href="https://www.facebook.com/sharer/sharer.php?u=http://springcloud.xn--ses554g/2020/04/13/JUC多线程及高并发/" data-title=" Facebook">
          <i class="icon icon-facebook"></i>
        </a>
      </li>
      <li>
        <a class="twitter share-sns" target="_blank" href="https://twitter.com/intent/tweet?text=《周阳-阳哥JUC多线程及高并发部分》 — Edward&url=http://springcloud.xn--ses554g/2020/04/13/JUC多线程及高并发/&via=http://springcloud.xn--ses554g" data-title=" Twitter">
          <i class="icon icon-twitter"></i>
        </a>
      </li>
      <li>
        <a class="google share-sns" target="_blank" href="https://plus.google.com/share?url=http://springcloud.xn--ses554g/2020/04/13/JUC多线程及高并发/" data-title=" Google+">
          <i class="icon icon-google-plus"></i>
        </a>
      </li>
    </ul>
 </div>


<div class="page-modal wx-share" id="wxShare">
    <a class="close" href="javascript:;"><i class="icon icon-close"></i></a>
    <p>扫一扫，分享到微信</p>
    <img src="" alt="微信分享二维码">
</div>




    <script src="//cdn.bootcss.com/node-waves/0.7.4/waves.min.js"></script>
<script>
var BLOG = { ROOT: '/', SHARE: true, REWARD: false };


</script>

<script src="//unpkg.com/hexo-theme-material-indigo@latest/js/main.min.js"></script>


<div class="search-panel" id="search-panel">
    <ul class="search-result" id="search-result"></ul>
</div>
<template id="search-tpl">
<li class="item">
    <a href="{path}" class="waves-block waves-effect">
        <div class="title ellipsis" title="{title}">{title}</div>
        <div class="flex-row flex-middle">
            <div class="tags ellipsis">
                {tags}
            </div>
            <time class="flex-col time">{date}</time>
        </div>
    </a>
</li>
</template>

<script src="//unpkg.com/hexo-theme-material-indigo@latest/js/search.min.js" async></script>






<script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>





<script src="/live2dw/lib/L2Dwidget.min.js?094cbace49a39548bed64abff5988b05"></script><script>L2Dwidget.init({"pluginRootPath":"live2dw/","pluginJsPath":"lib/","pluginModelPath":"assets/","tagMode":false,"log":false,"model":{"jsonPath":"/live2dw/assets/hijiki.model.json"},"display":{"position":"right","width":200,"height":400},"mobile":{"show":false}});</script></body>
</html>
